Check for required args first, and check for them all at once.
This is necessary for versions of Python <3.6, where dictionaries are unordered by default, meaning we can't ensure the order in which fields are checked.stix2.1
							parent
							
								
									1ba064734b
								
							
						
					
					
						commit
						5d7ed643bd
					
				| 
						 | 
				
			
			@ -61,7 +61,7 @@ will result in an error:
 | 
			
		|||
 | 
			
		||||
```python
 | 
			
		||||
>>> indicator = Indicator()
 | 
			
		||||
ValueError: Missing required field for Indicator: 'labels'
 | 
			
		||||
ValueError: Missing required field(s) for Indicator: (labels, pattern).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
However, the required `valid_from` attribute on Indicators will be set to the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,12 +74,15 @@ class _STIXBase(collections.Mapping):
 | 
			
		|||
        if extra_kwargs:
 | 
			
		||||
            raise TypeError("unexpected keyword arguments: " + str(extra_kwargs))
 | 
			
		||||
 | 
			
		||||
        required_fields = [k for k, v in cls._properties.items() if v.get('required')]
 | 
			
		||||
        missing_kwargs = set(required_fields) - set(kwargs)
 | 
			
		||||
        if missing_kwargs:
 | 
			
		||||
            msg = "Missing required field(s) for {type}: ({fields})."
 | 
			
		||||
            field_list = ", ".join(x for x in sorted(list(missing_kwargs)))
 | 
			
		||||
            raise ValueError(msg.format(type=class_name, fields=field_list))
 | 
			
		||||
 | 
			
		||||
        for prop_name, prop_metadata in cls._properties.items():
 | 
			
		||||
            if prop_name not in kwargs:
 | 
			
		||||
                if prop_metadata.get('required'):
 | 
			
		||||
                    msg = "Missing required field for {type}: '{field}'."
 | 
			
		||||
                    raise ValueError(msg.format(type=class_name,
 | 
			
		||||
                                                field=prop_name))
 | 
			
		||||
                if prop_metadata.get('default'):
 | 
			
		||||
                    default = prop_metadata['default']
 | 
			
		||||
                    if default == NOW:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -150,29 +150,28 @@ def test_indicator_autogenerated_fields(indicator):
 | 
			
		|||
 | 
			
		||||
def test_indicator_type_must_be_indicator():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        indicator = stix2.Indicator(type='xxx')
 | 
			
		||||
        indicator = stix2.Indicator(type='xxx', **INDICATOR_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Indicator must have type='indicator'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_indicator_id_must_start_with_indicator():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        indicator = stix2.Indicator(id='my-prefix--')
 | 
			
		||||
        indicator = stix2.Indicator(id='my-prefix--', **INDICATOR_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Indicator id values must begin with 'indicator--'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_indicator_required_field_labels():
 | 
			
		||||
def test_indicator_required_fields():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        indicator = stix2.Indicator()
 | 
			
		||||
    assert "Missing required field for Indicator: 'labels'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Indicator: (labels, pattern)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_indicator_required_field_pattern():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        # Label is checked first, so make sure that is provided
 | 
			
		||||
        indicator = stix2.Indicator(labels=['malicious-activity'])
 | 
			
		||||
    assert "Missing required field for Indicator: 'pattern'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Indicator: (pattern)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_cannot_assign_to_indicator_attributes(indicator):
 | 
			
		||||
| 
						 | 
				
			
			@ -240,29 +239,28 @@ def test_malware_autogenerated_fields(malware):
 | 
			
		|||
 | 
			
		||||
def test_malware_type_must_be_malware():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        malware = stix2.Malware(type='xxx')
 | 
			
		||||
        malware = stix2.Malware(type='xxx', **MALWARE_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Malware must have type='malware'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_malware_id_must_start_with_malware():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        malware = stix2.Malware(id='my-prefix--')
 | 
			
		||||
        malware = stix2.Malware(id='my-prefix--', **MALWARE_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Malware id values must begin with 'malware--'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_malware_required_field_labels():
 | 
			
		||||
def test_malware_required_fields():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        malware = stix2.Malware()
 | 
			
		||||
    assert "Missing required field for Malware: 'labels'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Malware: (labels, name)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_malware_required_field_name():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        # Label is checked first, so make sure that is provided
 | 
			
		||||
        malware = stix2.Malware(labels=['ransomware'])
 | 
			
		||||
    assert "Missing required field for Malware: 'name'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Malware: (name)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_cannot_assign_to_malware_attributes(malware):
 | 
			
		||||
| 
						 | 
				
			
			@ -324,14 +322,14 @@ def test_relationship_autogenerated_fields(relationship):
 | 
			
		|||
 | 
			
		||||
def test_relationship_type_must_be_relationship():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        relationship = stix2.Relationship(type='xxx')
 | 
			
		||||
        relationship = stix2.Relationship(type='xxx', **RELATIONSHIP_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Relationship must have type='relationship'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_relationship_id_must_start_with_relationship():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        relationship = stix2.Relationship(id='my-prefix--')
 | 
			
		||||
        relationship = stix2.Relationship(id='my-prefix--', **RELATIONSHIP_KWARGS)
 | 
			
		||||
 | 
			
		||||
    assert "Relationship id values must begin with 'relationship--'." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -339,24 +337,23 @@ def test_relationship_id_must_start_with_relationship():
 | 
			
		|||
def test_relationship_required_field_relationship_type():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        relationship = stix2.Relationship()
 | 
			
		||||
    assert "Missing required field for Relationship: 'relationship_type'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Relationship: (relationship_type, source_ref, target_ref)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_relationship_required_field_source_ref():
 | 
			
		||||
def test_relationship_missing_some_required_fields():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        # relationship_type is checked first, so make sure that is provided
 | 
			
		||||
        relationship = stix2.Relationship(relationship_type='indicates')
 | 
			
		||||
    assert "Missing required field for Relationship: 'source_ref'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Relationship: (source_ref, target_ref)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_relationship_required_field_target_ref():
 | 
			
		||||
    with pytest.raises(ValueError) as excinfo:
 | 
			
		||||
        # relationship_type and source_ref are checked first, so make sure those are provided
 | 
			
		||||
        relationship = stix2.Relationship(
 | 
			
		||||
            relationship_type='indicates',
 | 
			
		||||
            source_ref=INDICATOR_ID
 | 
			
		||||
        )
 | 
			
		||||
    assert "Missing required field for Relationship: 'target_ref'." in str(excinfo)
 | 
			
		||||
    assert "Missing required field(s) for Relationship: (target_ref)." in str(excinfo)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_cannot_assign_to_relationship_attributes(relationship):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue