diff --git a/stix2/base.py b/stix2/base.py
index cde8bb6..3f696fd 100644
--- a/stix2/base.py
+++ b/stix2/base.py
@@ -69,22 +69,19 @@ class _STIXBase(collections.Mapping):
         if list_of_properties and (not list_of_properties_populated or list_of_properties_populated == set(["extensions"])):
             raise AtLeastOnePropertyError(self.__class__, list_of_properties)
 
-    def _check_properties_dependency(self, list_of_properties, list_of_dependent_properties, values=[]):
+    def _check_properties_dependency(self, list_of_properties, list_of_dependent_properties):
         failed_dependency_pairs = []
-        current_properties = self.properties_populated()
         for p in list_of_properties:
-            v = values.pop() if values else None
             for dp in list_of_dependent_properties:
-                if dp in current_properties and (p not in current_properties or (v and not current_properties(p) == v)):
+                if not self.__getattr__(p) and self.__getattr__(dp):
                     failed_dependency_pairs.append((p, dp))
         if failed_dependency_pairs:
             raise DependentPropertiesError(self.__class__, failed_dependency_pairs)
 
     def _check_object_constraints(self):
-        if self.granular_markings:
-            for m in self.granular_markings:
-                # TODO: check selectors
-                pass
+        for m in self.get("granular_markings", []):
+            # TODO: check selectors
+            pass
 
     def __init__(self, **kwargs):
         cls = self.__class__
@@ -100,7 +97,7 @@ class _STIXBase(collections.Mapping):
         # Remove any keyword arguments whose value is None
         setting_kwargs = {}
         for prop_name, prop_value in kwargs.items():
-            if prop_value:
+            if prop_value is not None:
                 setting_kwargs[prop_name] = prop_value
 
         # Detect any missing required properties
@@ -127,11 +124,20 @@ class _STIXBase(collections.Mapping):
 
     # Handle attribute access just like key access
     def __getattr__(self, name):
-        return self.get(name)
+        try:
+            # Return attribute value.
+            return self.__getitem__(name)
+        except KeyError:
+            # If attribute not found, check if its a property of the object.
+            if name in self._properties:
+                return None
+
+            raise AttributeError("'%s' object has no attribute '%s'" %
+                                 (self.__class__.__name__, name))
 
     def __setattr__(self, name, value):
         if name != '_inner' and not name.startswith("_STIXBase__"):
-            raise ImmutableError
+            raise ImmutableError(self.__class__, name)
         super(_STIXBase, self).__setattr__(name, value)
 
     def __str__(self):
diff --git a/stix2/exceptions.py b/stix2/exceptions.py
index 5cbaae9..3043047 100644
--- a/stix2/exceptions.py
+++ b/stix2/exceptions.py
@@ -47,8 +47,14 @@ class ExtraPropertiesError(STIXError, TypeError):
 class ImmutableError(STIXError, ValueError):
     """Attempted to modify an object after creation"""
 
-    def __init__(self):
-        super(ImmutableError, self).__init__("Cannot modify properties after creation.")
+    def __init__(self, cls, key):
+        super(ImmutableError, self).__init__()
+        self.cls = cls
+        self.key = key
+
+    def __str__(self):
+        msg = "Cannot modify '{0.key}' property in '{0.cls.__name__}' after creation."
+        return msg.format(self)
 
 
 class DictionaryKeyError(STIXError, ValueError):

Forgot to instantiate ImmutableError
I'm guessing [this line](https://github.com/oasis-open/cti-python-stix2/blob/f937e2bb3f104e3cdf0578ed8323b2f7e39119a4/stix2/base.py#L99) should raise an instance of the exception class, not the class itself?
diff --git a/stix2/test/test_indicator.py b/stix2/test/test_indicator.py
index 99d34d7..5db50e6 100644
--- a/stix2/test/test_indicator.py
+++ b/stix2/test/test_indicator.py
@@ -129,7 +129,7 @@ def test_cannot_assign_to_indicator_attributes(indicator):
     with pytest.raises(stix2.exceptions.ImmutableError) as excinfo:
         indicator.valid_from = dt.datetime.now()
 
-    assert str(excinfo.value) == "Cannot modify properties after creation."
+    assert str(excinfo.value) == "Cannot modify 'valid_from' property in 'Indicator' after creation."
 
 
 def test_invalid_kwarg_to_indicator():
diff --git a/stix2/test/test_malware.py b/stix2/test/test_malware.py
index 8952769..266d012 100644
--- a/stix2/test/test_malware.py
+++ b/stix2/test/test_malware.py
@@ -92,7 +92,7 @@ def test_cannot_assign_to_malware_attributes(malware):
     with pytest.raises(stix2.exceptions.ImmutableError) as excinfo:
         malware.name = "Cryptolocker II"
 
-    assert str(excinfo.value) == "Cannot modify properties after creation."
+    assert str(excinfo.value) == "Cannot modify 'name' property in 'Malware' after creation."
 
 
 def test_invalid_kwarg_to_malware():
diff --git a/stix2/test/test_observed_data.py b/stix2/test/test_observed_data.py
index c47338f..f221494 100644
--- a/stix2/test/test_observed_data.py
+++ b/stix2/test/test_observed_data.py
@@ -764,8 +764,7 @@ def test_file_example_encryption_error():
     with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo:
         stix2.File(name="qwerty.dll",
                    is_encrypted=False,
-                   encryption_algorithm="AES128-CBC"
-                   )
+                   encryption_algorithm="AES128-CBC")
 
     assert excinfo.value.cls == stix2.File
     assert excinfo.value.dependencies == [("is_encrypted", "encryption_algorithm")]
diff --git a/stix2/test/test_relationship.py b/stix2/test/test_relationship.py
index 1e799bf..1ad792c 100644
--- a/stix2/test/test_relationship.py
+++ b/stix2/test/test_relationship.py
@@ -103,7 +103,7 @@ def test_cannot_assign_to_relationship_attributes(relationship):
     with pytest.raises(stix2.exceptions.ImmutableError) as excinfo:
         relationship.relationship_type = "derived-from"
 
-    assert str(excinfo.value) == "Cannot modify properties after creation."
+    assert str(excinfo.value) == "Cannot modify 'relationship_type' property in 'Relationship' after creation."
 
 
 def test_invalid_kwarg_to_relationship():

pip install -e .[dev]
parse_log_pytest
requirements.txt
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
bump2version==1.0.1
bumpversion==0.6.0
cachetools==5.5.2
certifi==2025.1.31
cfgv==3.4.0
chardet==5.2.0
charset-normalizer==3.4.1
colorama==0.4.6
coverage==7.8.0
distlib==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
identify==2.6.9
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
nodeenv==1.9.1
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
pre_commit==4.2.0
Pygments==2.19.1
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.2
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-prompt==1.8.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
-e git+https://github.com/oasis-open/cti-python-stix2.git@229ab5d323a412ee91e8462701c816e1dfc0d521#egg=stix2
tomli==2.2.1
tox==4.25.0
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
zipp==3.21.0

name: cti-python-stix2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - bump2version==1.0.1
      - bumpversion==0.6.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cfgv==3.4.0
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - colorama==0.4.6
      - coverage==7.8.0
      - distlib==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - identify==2.6.9
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - nodeenv==1.9.1
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pre-commit==4.2.0
      - pygments==2.19.1
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.2
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-prompt==1.8.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tox==4.25.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - zipp==3.21.0
prefix: /opt/conda/envs/cti-python-stix2

stix2/test/test_indicator.py::test_cannot_assign_to_indicator_attributes stix2/test/test_malware.py::test_cannot_assign_to_malware_attributes stix2/test/test_relationship.py::test_cannot_assign_to_relationship_attributes
stix2/test/test_indicator.py::test_indicator_with_all_required_properties stix2/test/test_indicator.py::test_indicator_autogenerated_properties stix2/test/test_indicator.py::test_indicator_type_must_be_indicator stix2/test/test_indicator.py::test_indicator_id_must_start_with_indicator stix2/test/test_indicator.py::test_indicator_required_properties stix2/test/test_indicator.py::test_indicator_required_property_pattern stix2/test/test_indicator.py::test_indicator_created_ref_invalid_format stix2/test/test_indicator.py::test_indicator_revoked_invalid stix2/test/test_indicator.py::test_invalid_kwarg_to_indicator stix2/test/test_indicator.py::test_created_modified_time_are_identical_by_default stix2/test/test_indicator.py::test_parse_indicator[{\n stix2/test/test_indicator.py::test_parse_indicator[data1] stix2/test/test_malware.py::test_malware_with_all_required_properties stix2/test/test_malware.py::test_malware_autogenerated_properties stix2/test/test_malware.py::test_malware_type_must_be_malware stix2/test/test_malware.py::test_malware_id_must_start_with_malware stix2/test/test_malware.py::test_malware_required_properties stix2/test/test_malware.py::test_malware_required_property_name stix2/test/test_malware.py::test_invalid_kwarg_to_malware stix2/test/test_malware.py::test_parse_malware[{\n stix2/test/test_malware.py::test_parse_malware[data1] stix2/test/test_malware.py::test_parse_malware_invalid_labels stix2/test/test_malware.py::test_parse_malware_kill_chain_phases stix2/test/test_malware.py::test_parse_malware_clean_kill_chain_phases stix2/test/test_observed_data.py::test_observed_data_example stix2/test/test_observed_data.py::test_observed_data_example_with_refs stix2/test/test_observed_data.py::test_observed_data_example_with_bad_refs stix2/test/test_observed_data.py::test_parse_observed_data[{\n stix2/test/test_observed_data.py::test_parse_observed_data[data1] stix2/test/test_observed_data.py::test_parse_artifact_valid["0": stix2/test/test_observed_data.py::test_parse_artifact_invalid["0": stix2/test/test_observed_data.py::test_parse_autonomous_system_valid["0": stix2/test/test_observed_data.py::test_parse_email_address[{\n stix2/test/test_observed_data.py::test_parse_email_message[\n stix2/test/test_observed_data.py::test_parse_file_archive["0": stix2/test/test_observed_data.py::test_parse_email_message_with_at_least_one_error[\n stix2/test/test_observed_data.py::test_parse_basic_tcp_traffic[\n stix2/test/test_observed_data.py::test_parse_basic_tcp_traffic_with_error[\n stix2/test/test_observed_data.py::test_observed_data_with_process_example stix2/test/test_observed_data.py::test_artifact_example stix2/test/test_observed_data.py::test_artifact_mutual_exclusion_error stix2/test/test_observed_data.py::test_directory_example stix2/test/test_observed_data.py::test_directory_example_ref_error stix2/test/test_observed_data.py::test_domain_name_example stix2/test/test_observed_data.py::test_domain_name_example_invalid_ref_type stix2/test/test_observed_data.py::test_file_example stix2/test/test_observed_data.py::test_file_example_with_NTFSExt stix2/test/test_observed_data.py::test_file_example_with_empty_NTFSExt stix2/test/test_observed_data.py::test_file_example_with_PDFExt stix2/test/test_observed_data.py::test_file_example_with_PDFExt_Object stix2/test/test_observed_data.py::test_file_example_with_RasterImageExt_Object stix2/test/test_observed_data.py::test_file_example_with_WindowsPEBinaryExt stix2/test/test_observed_data.py::test_file_example_encryption_error stix2/test/test_observed_data.py::test_ip4_address_example stix2/test/test_observed_data.py::test_ip4_address_example_cidr stix2/test/test_observed_data.py::test_ip6_address_example stix2/test/test_observed_data.py::test_mac_address_example stix2/test/test_observed_data.py::test_network_traffic_example stix2/test/test_observed_data.py::test_network_traffic_http_request_example stix2/test/test_observed_data.py::test_network_traffic_icmp_example stix2/test/test_observed_data.py::test_network_traffic_socket_example stix2/test/test_observed_data.py::test_network_traffic_tcp_example stix2/test/test_observed_data.py::test_mutex_example stix2/test/test_observed_data.py::test_process_example stix2/test/test_observed_data.py::test_process_example_empty_error stix2/test/test_observed_data.py::test_process_example_empty_with_extensions stix2/test/test_observed_data.py::test_process_example_windows_process_ext_empty stix2/test/test_observed_data.py::test_process_example_extensions_empty stix2/test/test_observed_data.py::test_process_example_with_WindowsProcessExt_Object stix2/test/test_observed_data.py::test_process_example_with_WindowsServiceExt stix2/test/test_observed_data.py::test_process_example_with_WindowsProcessServiceExt stix2/test/test_observed_data.py::test_software_example stix2/test/test_observed_data.py::test_url_example stix2/test/test_observed_data.py::test_user_account_example stix2/test/test_observed_data.py::test_user_account_unix_account_ext_example stix2/test/test_observed_data.py::test_windows_registry_key_example stix2/test/test_observed_data.py::test_x509_certificate_example stix2/test/test_relationship.py::test_relationship_all_required_properties stix2/test/test_relationship.py::test_relationship_autogenerated_properties stix2/test/test_relationship.py::test_relationship_type_must_be_relationship stix2/test/test_relationship.py::test_relationship_id_must_start_with_relationship stix2/test/test_relationship.py::test_relationship_required_property_relationship_type stix2/test/test_relationship.py::test_relationship_missing_some_required_properties stix2/test/test_relationship.py::test_relationship_required_properties_target_ref stix2/test/test_relationship.py::test_invalid_kwarg_to_relationship stix2/test/test_relationship.py::test_create_relationship_from_objects_rather_than_ids stix2/test/test_relationship.py::test_create_relationship_with_positional_args stix2/test/test_relationship.py::test_parse_relationship[{\n stix2/test/test_relationship.py::test_parse_relationship[data1]
stix2/exceptions.py stix2/base.py
stix2/exceptions.py stix2/base.py