)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":8,"id":"42a8d856_c9da9ac0","updated":"2026-07-29 19:40:24.000000000","message":"i think we can impove this but this is proably meragbale as is\n\nsome comments inline for you to consider","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1157e217bfe849a1ac75bb6a2889217ee8f768ba","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":12,"id":"91e73c7e_6143f882","updated":"2026-08-04 17:52:45.000000000","message":"i needto review this again when im a litte less tire bur this looks ok to me","commit_id":"45394c15cc7e07bc37be5e497e7441b0b4212102"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"5b648142288e54ffd6ddee69ebe03534494b70ed","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":13,"id":"5f5b02a0_e978af5c","updated":"2026-08-21 15:13:50.000000000","message":"i was actully expectign to merge this before you nvme serise but i guess we can merge itin this order","commit_id":"1d3a2a3076fae2024e1569acfb789c1938797b9b"}],"cyborg/accelerator/bus_managers/mdev.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"ecf42a3588da52e8a785d91aea8a5a0a98d902bc","unresolved":false,"context_lines":[{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises IOError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"}],"source_content_type":"text/x-python","patch_set":3,"id":"0490fb1a_879939b6","line":247,"updated":"2026-07-20 10:43:21.000000000","message":"The docstring for _read_sysfs_attr documents \u0027:raises IOError:\u0027 but open() in Python 3 raises OSError (which IOError aliases). All callers in the same module correctly catch OSError, so the docstring uses stale Python 2 terminology.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Minor: developers reading the docstring may use IOError in their except clauses, which works but is non-idiomatic for Python 3.\n\n**Recommendation**:\nChange \u0027:raises IOError:\u0027 to \u0027:raises OSError:\u0027 to match the actual exception and the rest of the codebase.","commit_id":"966f6480ef4d018168308fa537df3c6331ab2158"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"2c48c907e2618736db3c358a9735e0175b03da9a","unresolved":false,"context_lines":[{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises IOError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"}],"source_content_type":"text/x-python","patch_set":5,"id":"ab8e71f3_83f31315","line":247,"updated":"2026-07-22 12:23:47.000000000","message":"The _read_sysfs_attr docstring states \u0027:raises IOError:\u0027 but the project targets Python 3.10+ where OSError is the canonical exception name. While IOError is an alias for OSError in Python 3.3+, the caller (_read_mdev_type) catches OSError, so the docstring should use the same name for consistency.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Minor documentation inaccuracy. Readers familiar with Python 2 may be confused by the IOError reference, and the mismatch with the OSError catch in the caller is a minor clarity issue. No runtime impact since the two names are aliases.\n\n**Recommendation**:\nChange \u0027:raises IOError:\u0027 to \u0027:raises OSError:\u0027 in the _read_sysfs_attr docstring to match the Python 3 canonical name and the actual exception caught by callers.","commit_id":"ccaae3823ca22cf7a90d6e034fb1432cfab64aa4"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"e328e8eb0bfcf02639d07d0eba1030eb6529539f","unresolved":false,"context_lines":[{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises IOError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"}],"source_content_type":"text/x-python","patch_set":6,"id":"c9792461_920f568a","line":247,"updated":"2026-07-22 15:30:29.000000000","message":"The _read_sysfs_attr method docstring documents \u0027:raises IOError: If the file cannot be read.\u0027 In Python 3, IOError is an alias for OSError, but the actual exception raised by open() on a missing or unreadable file is OSError (or its subclass FileNotFoundError). Using the legacy Python 2 name in...\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Minor documentation clarity issue. A developer reading the docstring might import or catch IOError explicitly rather than OSError, or be confused about the actual exception hierarchy.\n\n**Recommendation**:\nChange \u0027:raises IOError:\u0027 to \u0027:raises OSError:\u0027 to match the actual exception type and the callers\u0027 catch clauses.","commit_id":"f5af120109fcc41d53dc016b1f0d5d9fbdf69d62"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3cf394cccc2efe80429bcf5e72a972832ef55010","unresolved":false,"context_lines":[{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises IOError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"}],"source_content_type":"text/x-python","patch_set":7,"id":"7c0531e4_06448c67","line":247,"updated":"2026-07-29 11:14:11.000000000","message":"The _read_sysfs_attr method\u0027s docstring states \u0027:raises IOError:\u0027 but the code and all callers in this module use OSError. In Python 3, IOError is a backward-compatibility alias for OSError; the canonical name is OSError. The docstring should reflect the actual exception type used in the code.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Developers reading the docstring may expect to catch IOError rather than OSError, causing confusion or incorrect exception handling in callers. The impact is low since IOError and OSError are the same in Python 3, but the naming inconsistency reduces documentation clarity.\n\n**Recommendation**:\nChange \u0027:raises IOError:\u0027 to \u0027:raises OSError:\u0027 in the _read_sysfs_attr docstring to match the actual exception type used throughout the module.","commit_id":"d9618f046671c4464f71873ebcbcbaaba1c9213c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":44,"context_line":"    def __init__(self, sysfs_path: str | None \u003d None):"},{"line_number":45,"context_line":"        self.sysfs_path: str \u003d sysfs_path or MDEV_BUS_SYSFS_PATH"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"    def discover_parent_devices("},{"line_number":48,"context_line":"        self,"},{"line_number":49,"context_line":"        pci_filter: list[str] | None \u003d None,"},{"line_number":50,"context_line":"    ) -\u003e list[str]:"},{"line_number":51,"context_line":"        \"\"\"Enumerate mdev-capable PCI parent devices."},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"        :param pci_filter: Controls which devices are returned."}],"source_content_type":"text/x-python","patch_set":8,"id":"7d8d64ca_27ec2ea9","line":50,"range":{"start_line":47,"start_character":2,"end_line":50,"end_character":19},"updated":"2026-07-29 19:40:24.000000000","message":"so this is curently what know as a stringly type interface rather then a stongly typed intereface.\n\ni would like us to move toward using dataclasess to model this\n\n\nso we would return an MdevParentDevce\n\nthat might start with only a adress but it probaly shoudl have a mdev_types property that returns a list of MdevType objects that has a aviable amount ectra.\n\nevenutlly we do not want to move waways form pasing string or dicts around internaly ot thse concreate types.","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":true,"context_lines":[{"line_number":44,"context_line":"    def __init__(self, sysfs_path: str | None \u003d None):"},{"line_number":45,"context_line":"        self.sysfs_path: str \u003d sysfs_path or MDEV_BUS_SYSFS_PATH"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"    def discover_parent_devices("},{"line_number":48,"context_line":"        self,"},{"line_number":49,"context_line":"        pci_filter: list[str] | None \u003d None,"},{"line_number":50,"context_line":"    ) -\u003e list[str]:"},{"line_number":51,"context_line":"        \"\"\"Enumerate mdev-capable PCI parent devices."},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"        :param pci_filter: Controls which devices are returned."}],"source_content_type":"text/x-python","patch_set":8,"id":"eabc5be4_aafbfd71","line":50,"range":{"start_line":47,"start_character":2,"end_line":50,"end_character":19},"in_reply_to":"7d8d64ca_27ec2ea9","updated":"2026-07-30 10:12:53.000000000","message":"sounds good, I\u0027ll add them in the next patchset","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1157e217bfe849a1ac75bb6a2889217ee8f768ba","unresolved":false,"context_lines":[{"line_number":44,"context_line":"    def __init__(self, sysfs_path: str | None \u003d None):"},{"line_number":45,"context_line":"        self.sysfs_path: str \u003d sysfs_path or MDEV_BUS_SYSFS_PATH"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"    def discover_parent_devices("},{"line_number":48,"context_line":"        self,"},{"line_number":49,"context_line":"        pci_filter: list[str] | None \u003d None,"},{"line_number":50,"context_line":"    ) -\u003e list[str]:"},{"line_number":51,"context_line":"        \"\"\"Enumerate mdev-capable PCI parent devices."},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"        :param pci_filter: Controls which devices are returned."}],"source_content_type":"text/x-python","patch_set":8,"id":"fcc10c57_28d3b58a","line":50,"range":{"start_line":47,"start_character":2,"end_line":50,"end_character":19},"in_reply_to":"eabc5be4_aafbfd71","updated":"2026-08-04 17:52:45.000000000","message":"Acknowledged","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":237,"context_line":"            \u0027description\u0027: description,"},{"line_number":238,"context_line":"        }"},{"line_number":239,"context_line":""},{"line_number":240,"context_line":"    @staticmethod"},{"line_number":241,"context_line":"    def _read_sysfs_attr(directory: str, filename: str) -\u003e str:"},{"line_number":242,"context_line":"        \"\"\"Read and strip a sysfs attribute file."},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises OSError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"},{"line_number":251,"context_line":"            return f.read().strip()"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"    @staticmethod"},{"line_number":254,"context_line":"    def _read_sysfs_attr_optional("},{"line_number":255,"context_line":"        directory: str,"},{"line_number":256,"context_line":"        filename: str,"},{"line_number":257,"context_line":"    ) -\u003e str:"},{"line_number":258,"context_line":"        \"\"\"Read a sysfs attribute file, returning \u0027\u0027 if absent."},{"line_number":259,"context_line":""},{"line_number":260,"context_line":"        :param directory: Directory containing the file."},{"line_number":261,"context_line":"        :param filename: Name of the file to read."},{"line_number":262,"context_line":"        :returns: The stripped file content, or ``\u0027\u0027`` if the file"},{"line_number":263,"context_line":"            does not exist."},{"line_number":264,"context_line":"        \"\"\""},{"line_number":265,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":266,"context_line":"        try:"},{"line_number":267,"context_line":"            with open(path) as f:"},{"line_number":268,"context_line":"                return f.read().strip()"},{"line_number":269,"context_line":"        except OSError:"},{"line_number":270,"context_line":"            return \u0027\u0027"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"    @staticmethod"},{"line_number":273,"context_line":"    def _count_created_instances(type_dir: str) -\u003e int:"},{"line_number":274,"context_line":"        \"\"\"Count mdev instances created for a given type."}],"source_content_type":"text/x-python","patch_set":8,"id":"cd88251d_a2f54395","line":271,"range":{"start_line":240,"start_character":3,"end_line":271,"end_character":1},"updated":"2026-07-29 19:40:24.000000000","message":"so in nova we used to often just do open like that\n\nand it mostly works but i built \n\nhttps://github.com/openstack/nova/blob/master/nova/filesystem.py\n\nto provide a more robust way to deal with this because real hardware will return DeviceBusy when vms dont\n\nwe got bit by that  by that when we did real hardware testing.\nhttps://github.com/openstack/nova/commit/44c1b48b3121682cf959c90b3adaf2a3f92e318c\n\ncan you port that in a followup and use it here\n\nevernally i want to put all our sysfs acces though those helpers\nso i would liek it to be its own imporabel untilty module rather then inliened here","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1157e217bfe849a1ac75bb6a2889217ee8f768ba","unresolved":false,"context_lines":[{"line_number":237,"context_line":"            \u0027description\u0027: description,"},{"line_number":238,"context_line":"        }"},{"line_number":239,"context_line":""},{"line_number":240,"context_line":"    @staticmethod"},{"line_number":241,"context_line":"    def _read_sysfs_attr(directory: str, filename: str) -\u003e str:"},{"line_number":242,"context_line":"        \"\"\"Read and strip a sysfs attribute file."},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises OSError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"},{"line_number":251,"context_line":"            return f.read().strip()"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"    @staticmethod"},{"line_number":254,"context_line":"    def _read_sysfs_attr_optional("},{"line_number":255,"context_line":"        directory: str,"},{"line_number":256,"context_line":"        filename: str,"},{"line_number":257,"context_line":"    ) -\u003e str:"},{"line_number":258,"context_line":"        \"\"\"Read a sysfs attribute file, returning \u0027\u0027 if absent."},{"line_number":259,"context_line":""},{"line_number":260,"context_line":"        :param directory: Directory containing the file."},{"line_number":261,"context_line":"        :param filename: Name of the file to read."},{"line_number":262,"context_line":"        :returns: The stripped file content, or ``\u0027\u0027`` if the file"},{"line_number":263,"context_line":"            does not exist."},{"line_number":264,"context_line":"        \"\"\""},{"line_number":265,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":266,"context_line":"        try:"},{"line_number":267,"context_line":"            with open(path) as f:"},{"line_number":268,"context_line":"                return f.read().strip()"},{"line_number":269,"context_line":"        except OSError:"},{"line_number":270,"context_line":"            return \u0027\u0027"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"    @staticmethod"},{"line_number":273,"context_line":"    def _count_created_instances(type_dir: str) -\u003e int:"},{"line_number":274,"context_line":"        \"\"\"Count mdev instances created for a given type."}],"source_content_type":"text/x-python","patch_set":8,"id":"822bceb3_77d20eea","line":271,"range":{"start_line":240,"start_character":3,"end_line":271,"end_character":1},"in_reply_to":"2938f2da_2fca6b40","updated":"2026-08-04 17:52:45.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":true,"context_lines":[{"line_number":237,"context_line":"            \u0027description\u0027: description,"},{"line_number":238,"context_line":"        }"},{"line_number":239,"context_line":""},{"line_number":240,"context_line":"    @staticmethod"},{"line_number":241,"context_line":"    def _read_sysfs_attr(directory: str, filename: str) -\u003e str:"},{"line_number":242,"context_line":"        \"\"\"Read and strip a sysfs attribute file."},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"        :param directory: Directory containing the file."},{"line_number":245,"context_line":"        :param filename: Name of the file to read."},{"line_number":246,"context_line":"        :returns: The stripped file content as a string."},{"line_number":247,"context_line":"        :raises OSError: If the file cannot be read."},{"line_number":248,"context_line":"        \"\"\""},{"line_number":249,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":250,"context_line":"        with open(path) as f:"},{"line_number":251,"context_line":"            return f.read().strip()"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"    @staticmethod"},{"line_number":254,"context_line":"    def _read_sysfs_attr_optional("},{"line_number":255,"context_line":"        directory: str,"},{"line_number":256,"context_line":"        filename: str,"},{"line_number":257,"context_line":"    ) -\u003e str:"},{"line_number":258,"context_line":"        \"\"\"Read a sysfs attribute file, returning \u0027\u0027 if absent."},{"line_number":259,"context_line":""},{"line_number":260,"context_line":"        :param directory: Directory containing the file."},{"line_number":261,"context_line":"        :param filename: Name of the file to read."},{"line_number":262,"context_line":"        :returns: The stripped file content, or ``\u0027\u0027`` if the file"},{"line_number":263,"context_line":"            does not exist."},{"line_number":264,"context_line":"        \"\"\""},{"line_number":265,"context_line":"        path \u003d os.path.join(directory, filename)"},{"line_number":266,"context_line":"        try:"},{"line_number":267,"context_line":"            with open(path) as f:"},{"line_number":268,"context_line":"                return f.read().strip()"},{"line_number":269,"context_line":"        except OSError:"},{"line_number":270,"context_line":"            return \u0027\u0027"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"    @staticmethod"},{"line_number":273,"context_line":"    def _count_created_instances(type_dir: str) -\u003e int:"},{"line_number":274,"context_line":"        \"\"\"Count mdev instances created for a given type."}],"source_content_type":"text/x-python","patch_set":8,"id":"2938f2da_2fca6b40","line":271,"range":{"start_line":240,"start_character":3,"end_line":271,"end_character":1},"in_reply_to":"cd88251d_a2f54395","updated":"2026-07-30 10:12:53.000000000","message":"ack, I prefer adding the filesystem helper in this change, we have already quite a few commits in the chain, I\u0027ll add it in the next patchset","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f4a9f7be897fe2c57b4d21f19310b550df6a76e4","unresolved":false,"context_lines":[{"line_number":275,"context_line":"        :returns: The stripped file content, or ``\u0027\u0027`` if the file"},{"line_number":276,"context_line":"            does not exist."},{"line_number":277,"context_line":"        \"\"\""},{"line_number":278,"context_line":"        try:"},{"line_number":279,"context_line":"            return filesystem.read_sys("},{"line_number":280,"context_line":"                directory / filename,"},{"line_number":281,"context_line":"            ).strip()"}],"source_content_type":"text/x-python","patch_set":12,"id":"5d4b2fdf_96aba611","line":278,"updated":"2026-08-04 16:45:17.000000000","message":"The _read_sysfs_attr_optional method catches both FileNotFound and DeviceBusy after exhausting all retries and returns an empty string without any log message. When a non-critical sysfs attribute (name or description) is persistently busy, the silent fallback masks intermittent hardware issues an...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Operators debugging mdev discovery issues on real hardware cannot distinguish between an attribute that is genuinely absent and one that was persistently busy after retries. This reduces diagnosability of kernel device model issues that the retry mechanism was specifically designed to handle.\n\n**Recommendation**:\nAdd a LOG.debug or LOG.warning call inside the except clause for the DeviceBusy case, noting the attribute name and device. At minimum, update the docstring to mention that DeviceBusy is also caught and mapped to empty string.","commit_id":"45394c15cc7e07bc37be5e497e7441b0b4212102"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1157e217bfe849a1ac75bb6a2889217ee8f768ba","unresolved":true,"context_lines":[{"line_number":275,"context_line":"        :returns: The stripped file content, or ``\u0027\u0027`` if the file"},{"line_number":276,"context_line":"            does not exist."},{"line_number":277,"context_line":"        \"\"\""},{"line_number":278,"context_line":"        try:"},{"line_number":279,"context_line":"            return filesystem.read_sys("},{"line_number":280,"context_line":"                directory / filename,"},{"line_number":281,"context_line":"            ).strip()"}],"source_content_type":"text/x-python","patch_set":12,"id":"8902150a_569103d6","line":278,"in_reply_to":"5d4b2fdf_96aba611","updated":"2026-08-04 17:52:45.000000000","message":"that not a terrible suggestion but not a blocker.\ni can see this beign useful at debug, maybe warnign but warnings should prompt the admin to do somthing.\n\na persitently busy device can indicate a hardware failure but its rare and this is a pretty weak signal in that case.","commit_id":"45394c15cc7e07bc37be5e497e7441b0b4212102"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1157e217bfe849a1ac75bb6a2889217ee8f768ba","unresolved":true,"context_lines":[{"line_number":300,"context_line":"        if not devices_dir.is_dir():"},{"line_number":301,"context_line":"            return 0"},{"line_number":302,"context_line":"        try:"},{"line_number":303,"context_line":"            return sum(1 for _ in devices_dir.iterdir())"},{"line_number":304,"context_line":"        except OSError:"},{"line_number":305,"context_line":"            return 0"}],"source_content_type":"text/x-python","patch_set":12,"id":"48a0d031_9f75a9f2","line":303,"range":{"start_line":303,"start_character":18,"end_line":303,"end_character":56},"updated":"2026-08-04 17:52:45.000000000","message":"nit: avoids the use of underscoer and is slightly simpler but its fine as is\n```suggestion\n            return len(list(devices_dir.iterdir()))\n```","commit_id":"45394c15cc7e07bc37be5e497e7441b0b4212102"}],"cyborg/tests/unit/accelerator/bus_managers/test_mdev.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"8131f9fa899302a5bfb3b55371081c0947380e8d","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        )"},{"line_number":395,"context_line":"        self.assertEqual([], result)"},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"    def test_created_instances_listdir_oserror(self):"},{"line_number":398,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":399,"context_line":"            self.sysfs,"},{"line_number":400,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":1,"id":"cb81879e_2a1ea5a8","line":397,"updated":"2026-07-13 13:53:58.000000000","message":"The test sets directory permissions to 0o000 to trigger an OSError from os.listdir, but when tests run as root filesystem permissions are ignored and os.listdir succeeds. The test passes for the wrong reason: an empty directory returns 0, not because the OSError path was exercised.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: The OSError handling branch in _count_created_instances (lines 288-290 of mdev.py) is not reliably tested. A regression in that error handling could go undetected when tests run as root.\n\n**Recommendation**:\nReplace the os.chmod approach with @mock.patch(\u0027os.listdir\u0027, side_effect\u003dOSError(\u0027denied\u0027), autospec\u003dTrue), consistent with the other OSError tests in this file. This ensures the error path is exercised deterministically regardless of the user running the tests.","commit_id":"122719520f303aa3ea52d3b25cedc2daaf01cae7"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f911ba8b9f6246584c2f9c258a15e0f532cdc14d","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        )"},{"line_number":395,"context_line":"        self.assertEqual([], result)"},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"    def test_created_instances_listdir_oserror(self):"},{"line_number":398,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":399,"context_line":"            self.sysfs,"},{"line_number":400,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":2,"id":"dfadbc44_034033e4","line":397,"updated":"2026-07-16 16:57:57.000000000","message":"The test creates an empty devices directory and sets mode 0o000, but the assertion passes regardless of whether OSError handling is exercised. As root (common in CI), chmod 0o000 does not prevent listdir. Even non-root, the empty dir means the success path also returns 0.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: A regression removing the \u0027except OSError: return 0\u0027 handler from _count_created_instances would not be caught by this test, giving false confidence in error-path coverage.\n\n**Recommendation**:\nEither populate the devices directory with fake instance symlinks before chmod so the success path returns a non-zero count, or mock os.listdir specifically for the _count_created_instances call to deterministically raise OSError, avoiding root/non-root variability.","commit_id":"a378358433b2fb5225b467c9cc78da7d0d336a1f"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"ecf42a3588da52e8a785d91aea8a5a0a98d902bc","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        )"},{"line_number":395,"context_line":"        self.assertEqual([], result)"},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"    def test_created_instances_listdir_oserror(self):"},{"line_number":398,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":399,"context_line":"            self.sysfs,"},{"line_number":400,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":3,"id":"7a22f1ee_05e44a4d","line":397,"updated":"2026-07-20 10:43:21.000000000","message":"The test uses os.chmod(devices_dir, 0o000) to simulate a permission-denied OSError in _count_created_instances, but root bypasses POSIX permission checks. In CI containers that run as root, os.listdir succeeds (returning the empty dir), so the test passes by coincidence without exercising the OSE...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: The OSError handling path in _count_created_instances (mdev.py:287-290) has no reliable test coverage. A regression in that error handler would go undetected in root-based CI environments.\n\n**Suggestion**:\nReplace the chmod-based approach with @mock.patch(\u0027os.listdir\u0027, side_effect\u003dOSError(\u0027denied\u0027), autospec\u003dTrue) scoped to _count_created_instances, consistent with the existing test_listdir_oserror and test_get_mdev_types_listdir_oserror patterns in the same file.","commit_id":"966f6480ef4d018168308fa537df3c6331ab2158"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"e328e8eb0bfcf02639d07d0eba1030eb6529539f","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        )"},{"line_number":395,"context_line":"        self.assertEqual([], result)"},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"    def test_created_instances_listdir_oserror(self):"},{"line_number":398,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":399,"context_line":"            self.sysfs,"},{"line_number":400,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":6,"id":"3713b806_952884ff","line":397,"updated":"2026-07-22 15:30:29.000000000","message":"The test uses os.chmod(devices_dir, 0o000) to simulate a permission-denied OSError from os.listdir. This approach is fragile: when tests run as root (common in some CI configurations), filesystem permission checks are bypassed and os.listdir succeeds, so the OSError handling path in _count_create...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: The error-handling path in _count_created_instances may go untested in CI environments where tests run as root, masking potential regressions in that code path.\n\n**Suggestion**:\nReplace the os.chmod approach with @mock.patch(\u0027os.listdir\u0027, side_effect\u003dOSError(\u0027denied\u0027), autospec\u003dTrue), consistent with the other listdir error tests in this file. The mock should be scoped to the _count_created_instances call specifically.","commit_id":"f5af120109fcc41d53dc016b1f0d5d9fbdf69d62"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"\"\"\"Unit tests for the MdevBusManager sysfs handler.\"\"\""},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import os"},{"line_number":16,"context_line":"import shutil"},{"line_number":17,"context_line":"import tempfile"},{"line_number":18,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"64e60548_858827cc","line":15,"range":{"start_line":15,"start_character":7,"end_line":15,"end_character":9},"updated":"2026-07-29 19:40:24.000000000","message":"nit: we shoudl prefer pathlib over os in general \n\nhttps://docs.python.org/3/library/pathlib.html\n\npathlib is the higher lever interface to workign with files and path\n\nos.path and os are ok but pathlib is less error prone\n\nhttps://docs.python.org/3/library/pathlib.html#corresponding-tools","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"\"\"\"Unit tests for the MdevBusManager sysfs handler.\"\"\""},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import os"},{"line_number":16,"context_line":"import shutil"},{"line_number":17,"context_line":"import tempfile"},{"line_number":18,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"393dddaa_09033706","line":15,"range":{"start_line":15,"start_character":7,"end_line":15,"end_character":9},"in_reply_to":"64e60548_858827cc","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def setUp(self):"},{"line_number":38,"context_line":"        super().setUp()"},{"line_number":39,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":40,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":41,"context_line":"        # Create two fake parent devices"},{"line_number":42,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:06:00.0\u0027))"},{"line_number":43,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:07:00.0\u0027))"}],"source_content_type":"text/x-python","patch_set":8,"id":"02462446_8bea81a1","line":40,"range":{"start_line":39,"start_character":1,"end_line":40,"end_character":50},"updated":"2026-07-29 19:40:24.000000000","message":"this will work but i generally prefer using the tempdir fixture\n\nhttps://github.com/testing-cabal/fixtures/blob/master/fixtures/_fixtures/tempdir.py#L28\n\n\nwith that said we do also already use\n\nNestedTempfile as a sideffect of the db fixture \n\nhttps://github.com/openstack/cyborg/blob/65c76dc8188a2c0d6c838751c92395b0e660c8b2/cyborg/tests/local_fixtures/db_fixture.py#L47\n\nwe might want to move the into the base test classs actully but \n\ngernelaly i fine the \n\nself.useFixutre patther to be less error prone because you cant forget the cleanup\n\n```\nself.sysfs \u003d self.useFixture(fixtures.TempDir).path\n```\n\nor\n```\nself.sysfs \u003d pathlib.Path(self.useFixture(fixtures.TempDir).path)\n```","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def setUp(self):"},{"line_number":38,"context_line":"        super().setUp()"},{"line_number":39,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":40,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":41,"context_line":"        # Create two fake parent devices"},{"line_number":42,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:06:00.0\u0027))"},{"line_number":43,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:07:00.0\u0027))"}],"source_content_type":"text/x-python","patch_set":8,"id":"2c94f565_ee2e1e31","line":40,"range":{"start_line":39,"start_character":1,"end_line":40,"end_character":50},"in_reply_to":"02462446_8bea81a1","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":38,"context_line":"        super().setUp()"},{"line_number":39,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":40,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":41,"context_line":"        # Create two fake parent devices"},{"line_number":42,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:06:00.0\u0027))"},{"line_number":43,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:07:00.0\u0027))"},{"line_number":44,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def test_filter_none_returns_empty(self):"}],"source_content_type":"text/x-python","patch_set":8,"id":"8719a330_b5936744","line":43,"range":{"start_line":41,"start_character":0,"end_line":43,"end_character":61},"updated":"2026-07-29 19:40:24.000000000","message":"we may want to facto this out into a resuabel sysfs fixtre in the future just an fyi","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":38,"context_line":"        super().setUp()"},{"line_number":39,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":40,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":41,"context_line":"        # Create two fake parent devices"},{"line_number":42,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:06:00.0\u0027))"},{"line_number":43,"context_line":"        os.makedirs(os.path.join(self.sysfs, \u00270000:07:00.0\u0027))"},{"line_number":44,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def test_filter_none_returns_empty(self):"}],"source_content_type":"text/x-python","patch_set":8,"id":"2f25baf7_8b94c128","line":43,"range":{"start_line":41,"start_character":0,"end_line":43,"end_character":61},"in_reply_to":"8719a330_b5936744","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    def test_nonexistent_sysfs_path(self):"},{"line_number":72,"context_line":"        mgr \u003d MdevBusManager("},{"line_number":73,"context_line":"            sysfs_path\u003d\u0027/nonexistent/path/mdev_bus\u0027,"},{"line_number":74,"context_line":"        )"},{"line_number":75,"context_line":"        result \u003d mgr.discover_parent_devices("},{"line_number":76,"context_line":"            pci_filter\u003d[\u0027*\u0027],"}],"source_content_type":"text/x-python","patch_set":8,"id":"fecfe84f_b6a36f3f","line":73,"range":{"start_line":73,"start_character":24,"end_line":73,"end_character":49},"updated":"2026-07-29 19:40:24.000000000","message":"this shoudl be a path under the temp dir.\n\nin this case its \"safe\" but it a bath practic to use hard coded path like this that could techhinly be really\n\nwhever weo decied to allow open to be called witout mockign it we need to do that in a temp dir create by the test altheritnlvy you can mock the filesystme acces to make it correct\n```suggestion\n            sysfs_path\u003d self.path +\u0027/nonexistent/path/mdev_bus\u0027,\n```","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    def test_nonexistent_sysfs_path(self):"},{"line_number":72,"context_line":"        mgr \u003d MdevBusManager("},{"line_number":73,"context_line":"            sysfs_path\u003d\u0027/nonexistent/path/mdev_bus\u0027,"},{"line_number":74,"context_line":"        )"},{"line_number":75,"context_line":"        result \u003d mgr.discover_parent_devices("},{"line_number":76,"context_line":"            pci_filter\u003d[\u0027*\u0027],"}],"source_content_type":"text/x-python","patch_set":8,"id":"ba691426_e339efe3","line":73,"range":{"start_line":73,"start_character":24,"end_line":73,"end_character":49},"in_reply_to":"fecfe84f_b6a36f3f","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":78,"context_line":"        self.assertEqual([], result)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    def test_empty_sysfs_directory(self):"},{"line_number":81,"context_line":"        empty_sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":82,"context_line":"        self.addCleanup(shutil.rmtree, empty_sysfs)"},{"line_number":83,"context_line":"        mgr \u003d MdevBusManager(sysfs_path\u003dempty_sysfs)"},{"line_number":84,"context_line":"        result \u003d mgr.discover_parent_devices("},{"line_number":85,"context_line":"            pci_filter\u003d[\u0027*\u0027],"}],"source_content_type":"text/x-python","patch_set":8,"id":"34a99e32_80cc7afd","line":82,"range":{"start_line":81,"start_character":6,"end_line":82,"end_character":51},"updated":"2026-07-29 19:40:24.000000000","message":"again i would use self.useFixture ...","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":78,"context_line":"        self.assertEqual([], result)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    def test_empty_sysfs_directory(self):"},{"line_number":81,"context_line":"        empty_sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":82,"context_line":"        self.addCleanup(shutil.rmtree, empty_sysfs)"},{"line_number":83,"context_line":"        mgr \u003d MdevBusManager(sysfs_path\u003dempty_sysfs)"},{"line_number":84,"context_line":"        result \u003d mgr.discover_parent_devices("},{"line_number":85,"context_line":"            pci_filter\u003d[\u0027*\u0027],"}],"source_content_type":"text/x-python","patch_set":8,"id":"a1c2275c_8fdc9dcb","line":82,"range":{"start_line":81,"start_character":6,"end_line":82,"end_character":51},"in_reply_to":"34a99e32_80cc7afd","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":120,"context_line":""},{"line_number":121,"context_line":"    def setUp(self):"},{"line_number":122,"context_line":"        super().setUp()"},{"line_number":123,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":124,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":125,"context_line":"        self.pci_addr \u003d \u00270000:06:00.0\u0027"},{"line_number":126,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"0fd82bfe_dced2365","line":123,"updated":"2026-07-29 19:40:24.000000000","message":"same here","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":120,"context_line":""},{"line_number":121,"context_line":"    def setUp(self):"},{"line_number":122,"context_line":"        super().setUp()"},{"line_number":123,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":124,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":125,"context_line":"        self.pci_addr \u003d \u00270000:06:00.0\u0027"},{"line_number":126,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"55d1c5c1_3329f6bd","line":123,"in_reply_to":"0fd82bfe_dced2365","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":122,"context_line":"        super().setUp()"},{"line_number":123,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":124,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":125,"context_line":"        self.pci_addr \u003d \u00270000:06:00.0\u0027"},{"line_number":126,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"},{"line_number":127,"context_line":"        self._create_mdev_type("},{"line_number":128,"context_line":"            self.pci_addr,"},{"line_number":129,"context_line":"            \u0027nvidia-319\u0027,"},{"line_number":130,"context_line":"            name\u003d\u0027GRID V100-1Q\u0027,"},{"line_number":131,"context_line":"            available\u003d\u002716\u0027,"},{"line_number":132,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":133,"context_line":"            description\u003d\u0027num_heads\u003d4, ram\u003d1024M\u0027,"},{"line_number":134,"context_line":"        )"},{"line_number":135,"context_line":"        self._create_mdev_type("},{"line_number":136,"context_line":"            self.pci_addr,"},{"line_number":137,"context_line":"            \u0027nvidia-320\u0027,"},{"line_number":138,"context_line":"            name\u003d\u0027GRID V100-2Q\u0027,"},{"line_number":139,"context_line":"            available\u003d\u00278\u0027,"},{"line_number":140,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":141,"context_line":"        )"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _create_mdev_type("},{"line_number":144,"context_line":"        self,"}],"source_content_type":"text/x-python","patch_set":8,"id":"783da733_57a9ce6f","line":141,"range":{"start_line":125,"start_character":4,"end_line":141,"end_character":9},"updated":"2026-07-29 19:40:24.000000000","message":"for now this is fine but as noted we may want to make this a reusable fixture later\n\ni can see the genreic ablity to create a sysfs tree with device beign useful for funtional tests in the futre\n\ntying this into my stringly typed interface cojmment \n\nif w ehad a MdevParentDevice dataclase this function\ncould take an instnac of that and project they sysfs view form that right\n\n\nso you would controct the logical obejct with its sub filed ectra and in the test we can have helper fucntion to stubout the corresponding sysfs view.\n\n\ni assume thes values came form nova at somepoint?\n\ni.e. the nivida mdevtype numbers/names\n\ni wonder if it would be better to use the mdpy or mtty example sform the kernel sampel apps instead?","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":true,"context_lines":[{"line_number":122,"context_line":"        super().setUp()"},{"line_number":123,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":124,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":125,"context_line":"        self.pci_addr \u003d \u00270000:06:00.0\u0027"},{"line_number":126,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"},{"line_number":127,"context_line":"        self._create_mdev_type("},{"line_number":128,"context_line":"            self.pci_addr,"},{"line_number":129,"context_line":"            \u0027nvidia-319\u0027,"},{"line_number":130,"context_line":"            name\u003d\u0027GRID V100-1Q\u0027,"},{"line_number":131,"context_line":"            available\u003d\u002716\u0027,"},{"line_number":132,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":133,"context_line":"            description\u003d\u0027num_heads\u003d4, ram\u003d1024M\u0027,"},{"line_number":134,"context_line":"        )"},{"line_number":135,"context_line":"        self._create_mdev_type("},{"line_number":136,"context_line":"            self.pci_addr,"},{"line_number":137,"context_line":"            \u0027nvidia-320\u0027,"},{"line_number":138,"context_line":"            name\u003d\u0027GRID V100-2Q\u0027,"},{"line_number":139,"context_line":"            available\u003d\u00278\u0027,"},{"line_number":140,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":141,"context_line":"        )"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _create_mdev_type("},{"line_number":144,"context_line":"        self,"}],"source_content_type":"text/x-python","patch_set":8,"id":"84e82072_22ec2642","line":141,"range":{"start_line":125,"start_character":4,"end_line":141,"end_character":9},"in_reply_to":"783da733_57a9ce6f","updated":"2026-07-30 10:12:53.000000000","message":"ack, I refactored the functions that created teh fake mdev files into a fixture. With respect to the names, I just left the values that clauded picked, since I did not think the actual values are important. We mentioned some nvidia mdev types in the spec, so I guess it got them from there.","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"818ba80e99b9d40995b1a349e6d3e9eeda707b30","unresolved":false,"context_lines":[{"line_number":122,"context_line":"        super().setUp()"},{"line_number":123,"context_line":"        self.sysfs \u003d tempfile.mkdtemp(prefix\u003d\u0027mdev_bus_\u0027)"},{"line_number":124,"context_line":"        self.addCleanup(shutil.rmtree, self.sysfs)"},{"line_number":125,"context_line":"        self.pci_addr \u003d \u00270000:06:00.0\u0027"},{"line_number":126,"context_line":"        self.mgr \u003d MdevBusManager(sysfs_path\u003dself.sysfs)"},{"line_number":127,"context_line":"        self._create_mdev_type("},{"line_number":128,"context_line":"            self.pci_addr,"},{"line_number":129,"context_line":"            \u0027nvidia-319\u0027,"},{"line_number":130,"context_line":"            name\u003d\u0027GRID V100-1Q\u0027,"},{"line_number":131,"context_line":"            available\u003d\u002716\u0027,"},{"line_number":132,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":133,"context_line":"            description\u003d\u0027num_heads\u003d4, ram\u003d1024M\u0027,"},{"line_number":134,"context_line":"        )"},{"line_number":135,"context_line":"        self._create_mdev_type("},{"line_number":136,"context_line":"            self.pci_addr,"},{"line_number":137,"context_line":"            \u0027nvidia-320\u0027,"},{"line_number":138,"context_line":"            name\u003d\u0027GRID V100-2Q\u0027,"},{"line_number":139,"context_line":"            available\u003d\u00278\u0027,"},{"line_number":140,"context_line":"            device_api\u003d\u0027vfio-pci\u0027,"},{"line_number":141,"context_line":"        )"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _create_mdev_type("},{"line_number":144,"context_line":"        self,"}],"source_content_type":"text/x-python","patch_set":8,"id":"7273d609_90ed0ba9","line":141,"range":{"start_line":125,"start_character":4,"end_line":141,"end_character":9},"in_reply_to":"84e82072_22ec2642","updated":"2026-08-18 12:18:26.000000000","message":"Acknowledged","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"a975b204fda91be38b4f81d18c4df7687735276f","unresolved":true,"context_lines":[{"line_number":175,"context_line":"                description,"},{"line_number":176,"context_line":"            )"},{"line_number":177,"context_line":""},{"line_number":178,"context_line":"    def _create_mdev_instances("},{"line_number":179,"context_line":"        self,"},{"line_number":180,"context_line":"        pci_addr,"},{"line_number":181,"context_line":"        type_name,"},{"line_number":182,"context_line":"        count,"},{"line_number":183,"context_line":"    ):"},{"line_number":184,"context_line":"        \"\"\"Create fake mdev instance symlinks in devices/.\"\"\""},{"line_number":185,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":186,"context_line":"            self.sysfs,"},{"line_number":187,"context_line":"            pci_addr,"},{"line_number":188,"context_line":"            \u0027mdev_supported_types\u0027,"},{"line_number":189,"context_line":"            type_name,"},{"line_number":190,"context_line":"            \u0027devices\u0027,"},{"line_number":191,"context_line":"        )"},{"line_number":192,"context_line":"        os.makedirs(devices_dir, exist_ok\u003dTrue)"},{"line_number":193,"context_line":"        for i in range(count):"},{"line_number":194,"context_line":"            uuid \u003d f\u002700000000-0000-0000-0000-{i:012d}\u0027"},{"line_number":195,"context_line":"            os.symlink(\u0027/dev/null\u0027, os.path.join(devices_dir, uuid))"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    def test_filter_none_returns_empty(self):"},{"line_number":198,"context_line":"        result \u003d self.mgr.get_mdev_types("},{"line_number":199,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":8,"id":"e4ae910e_77575255","line":196,"range":{"start_line":178,"start_character":4,"end_line":196,"end_character":1},"updated":"2026-07-29 19:40:24.000000000","message":"we do not need to use symlinks here we just need to touch the file\n\n```suggestion\nimport pathlib\n\n\ndef _create_mdev_instances(\n    self,\n    pci_addr: str,\n    type_name: str,\n    count: int,\n) -\u003e None:\n    \"\"\"Create fake mdev instance files in devices/.\"\"\"\n    devices_dir \u003d (\n        pathlib.Path(self.sysfs)\n        / pci_addr\n        / \"mdev_supported_types\"\n        / type_name\n        / \"devices\"\n    )\n\n    # Ensure parent directory hierarchy exists\n    devices_dir.mkdir(parents\u003dTrue, exist_ok\u003dTrue)\n\n    for i in range(count):\n        uuid \u003d f\"00000000-0000-0000-0000-{i:012d}\"\n\n        # Touch the file (creates an empty file or updates mtime if it exists)\n        (devices_dir / uuid).touch()\n```","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6193cbb8bd57bb94201acf141799c2abd7aa48ce","unresolved":false,"context_lines":[{"line_number":175,"context_line":"                description,"},{"line_number":176,"context_line":"            )"},{"line_number":177,"context_line":""},{"line_number":178,"context_line":"    def _create_mdev_instances("},{"line_number":179,"context_line":"        self,"},{"line_number":180,"context_line":"        pci_addr,"},{"line_number":181,"context_line":"        type_name,"},{"line_number":182,"context_line":"        count,"},{"line_number":183,"context_line":"    ):"},{"line_number":184,"context_line":"        \"\"\"Create fake mdev instance symlinks in devices/.\"\"\""},{"line_number":185,"context_line":"        devices_dir \u003d os.path.join("},{"line_number":186,"context_line":"            self.sysfs,"},{"line_number":187,"context_line":"            pci_addr,"},{"line_number":188,"context_line":"            \u0027mdev_supported_types\u0027,"},{"line_number":189,"context_line":"            type_name,"},{"line_number":190,"context_line":"            \u0027devices\u0027,"},{"line_number":191,"context_line":"        )"},{"line_number":192,"context_line":"        os.makedirs(devices_dir, exist_ok\u003dTrue)"},{"line_number":193,"context_line":"        for i in range(count):"},{"line_number":194,"context_line":"            uuid \u003d f\u002700000000-0000-0000-0000-{i:012d}\u0027"},{"line_number":195,"context_line":"            os.symlink(\u0027/dev/null\u0027, os.path.join(devices_dir, uuid))"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    def test_filter_none_returns_empty(self):"},{"line_number":198,"context_line":"        result \u003d self.mgr.get_mdev_types("},{"line_number":199,"context_line":"            self.pci_addr,"}],"source_content_type":"text/x-python","patch_set":8,"id":"8ef5da64_5894c11b","line":196,"range":{"start_line":178,"start_character":4,"end_line":196,"end_character":1},"in_reply_to":"e4ae910e_77575255","updated":"2026-07-30 10:12:53.000000000","message":"Done","commit_id":"9891fe20277ad8b0cbf9ad6c8d5f111a6fcb9254"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"fd5a36738841a352d42d57e9dc86620ee248b40b","unresolved":false,"context_lines":[{"line_number":84,"context_line":"        )"},{"line_number":85,"context_line":"        self.assertEqual([], result)"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    @mock.patch(\u0027os.listdir\u0027, side_effect\u003dOSError(\u0027denied\u0027), autospec\u003dTrue)"},{"line_number":88,"context_line":"    def test_listdir_oserror(self, mock_listdir):"},{"line_number":89,"context_line":"        result \u003d self.mgr.discover_parent_devices("},{"line_number":90,"context_line":"            pci_filter\u003d[\u0027*\u0027],"}],"source_content_type":"text/x-python","patch_set":9,"id":"11973076_60a959f0","line":87,"updated":"2026-07-30 11:36:12.000000000","message":"Two tests that claim to verify OSError handling during sysfs directory listing mock os.listdir, but MdevBusManager uses pathlib.Path.iterdir() which calls os.scandir() internally. The mocks have no effect, so the tests will fail because iterdir succeeds and returns real entries while the tests ex...\n\n**Severity**: HIGH | **Confidence**: 0.9\n\n**Risk**: Both test_listdir_oserror and test_get_mdev_types_listdir_oserror will fail in CI because the mock does not trigger the intended OSError. The OSError handling path in discover_parent_devices and get_mdev_types is left completely untested.\n\n**Priority**: Before merge\n**Why This Matters**: Both test_listdir_oserror and test_get_mdev_types_listdir_oserror will fail in CI because the mock does not trigger the intended OSError. The OSError handling path in discover_parent_devices and get_mdev_types is left completely untested.\n\n**Recommendation**:\nReplace mock.patch(\u0027os.listdir\u0027, ...) with a mock of pathlib.Path.iterdir or os.scandir. For example: @mock.patch.object(pathlib.Path, \u0027iterdir\u0027, side_effect\u003dOSError(\u0027denied\u0027)). Alternatively, mock os.scandir to return a context manager whose __enter__ raises OSError.","commit_id":"adb39e621a1912be65cc538af38a60b7c8a14ff2"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"1d28809291d1e03b75ff46aca8a178926262e0c4","unresolved":false,"context_lines":[{"line_number":355,"context_line":"        )"},{"line_number":356,"context_line":"        self.assertEqual([], result)"},{"line_number":357,"context_line":""},{"line_number":358,"context_line":"    def test_created_instances_listdir_oserror(self):"},{"line_number":359,"context_line":"        devices_dir \u003d ("},{"line_number":360,"context_line":"            pathlib.Path(self.sysfs)"},{"line_number":361,"context_line":"            / self.pci_addr"}],"source_content_type":"text/x-python","patch_set":11,"id":"5752b1f2_3e54bca4","line":358,"updated":"2026-08-03 08:39:22.000000000","message":"The test relies on chmod(0o000) to make a directory unreadable so that iterdir() raises OSError. When the test suite runs as root (common in some CI containers), the permission bits are ignored and iterdir() succeeds, returning an empty directory. The assertion passes for the wrong reason and the...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: A regression in the OSError handling of _count_created_instances would go undetected in root-running CI environments, giving false confidence in error-path coverage.\n\n**Suggestion**:\nReplace the chmod approach with mock.patch(\u0027pathlib.Path.iterdir\u0027, side_effect\u003dOSError(\u0027denied\u0027), autospec\u003dTrue), consistent with test_get_mdev_types_listdir_oserror and test_listdir_oserror in the same file.","commit_id":"5317fcda5fc839e020716e14235dd9d0c64168d3"}]}
