# Path: pandasdmx/message.py
# class StructureMessage(Message):
#     #: Collection of :class:`.Categorisation`.
#     categorisation: DictLike[str, model.Categorisation] = dictlike_field()
#     #: Collection of :class:`.CategoryScheme`.
#     category_scheme: DictLike[str, model.CategoryScheme] = dictlike_field()
#     #: Collection of :class:`.Codelist`.
#     codelist: DictLike[str, model.Codelist] = dictlike_field()
#     #: Collection of :class:`.ConceptScheme`.
#     concept_scheme: DictLike[str, model.ConceptScheme] = dictlike_field()
#     #: Collection of :class:`.ContentConstraint`.
#     constraint: DictLike[str, model.ContentConstraint] = dictlike_field()
#     #: Collection of :class:`.DataflowDefinition`.
#     dataflow: DictLike[str, model.DataflowDefinition] = dictlike_field()
#     #: Collection of :class:`.DataStructureDefinition`.
#     structure: DictLike[str, model.DataStructureDefinition] = dictlike_field()
#     #: Collection of :class:`.AgencyScheme`.
#     organisation_scheme: DictLike[str, model.AgencyScheme] = dictlike_field()
#     #: Collection of :class:`.ProvisionAgreement`.
#     provisionagreement: DictLike[str, model.ProvisionAgreement] = dictlike_field()
# 
#     def compare(self, other, strict=True):
#         """Return :obj:`True` if `self` is the same as `other`.
# 
#         Two StructureMessages compare equal if :meth:`.DictLike.compare` is :obj:`True`
#         for each of the object collection attributes.
# 
#         Parameters
#         ----------
#         strict : bool, optional
#             Passed to :meth:`.DictLike.compare`.
#         """
#         return super().compare(other, strict) and all(
#             getattr(self, f).compare(getattr(other, f), strict)
#             for f in direct_fields(self.__class__).keys()
#         )
# 
#     def add(self, obj: model.IdentifiableArtefact):
#         """Add `obj` to the StructureMessage."""
#         for field, field_info in direct_fields(self.__class__).items():
#             # NB for some reason mypy complains here, but not in __contains__(), below
#             if isinstance(
#                 obj, get_args(field_info.outer_type_)[1],  # type: ignore [attr-defined]
#             ):
#                 getattr(self, field)[obj.id] = obj
#                 return
#         raise TypeError(type(obj))
# 
#     def get(
#         self, obj_or_id: Union[str, model.IdentifiableArtefact]
#     ) -> Optional[model.IdentifiableArtefact]:
#         """Retrieve `obj_or_id` from the StructureMessage.
# 
#         Parameters
#         ----------
#         obj_or_id : str or .IdentifiableArtefact
#             If an IdentifiableArtefact, return an object of the same class and
#             :attr:`~.IdentifiableArtefact.id`; if :class:`str`, an object with this ID.
# 
#         Returns
#         -------
#         .IdentifiableArtefact
#             with the given ID and possibly class.
#         None
#             if there is no match.
# 
#         Raises
#         ------
#         ValueError
#             if `obj_or_id` is a string and there are ≥2 objects (of different classes)
#             with the same ID.
#         """
#         id = (
#             obj_or_id.id
#             if isinstance(obj_or_id, model.IdentifiableArtefact)
#             else obj_or_id
#         )
# 
#         candidates: List[model.IdentifiableArtefact] = list(
#             filter(
#                 None,
#                 map(
#                     lambda f: getattr(self, f).get(id),
#                     direct_fields(self.__class__).keys(),
#                 ),
#             )
#         )
# 
#         if len(candidates) > 1:
#             raise ValueError(f"ambiguous; {repr(obj_or_id)} matches {repr(candidates)}")
# 
#         return candidates[0] if len(candidates) == 1 else None
# 
#     def objects(self, cls):
#         """Get a reference to the attribute for objects of type `cls`.
# 
#         For example, if `cls` is the class :class:`DataStructureDefinition` (not an
#         instance), return a reference to :attr:`structure`.
#         """
#         for name, info in direct_fields(self.__class__).items():
#             if issubclass(cls, info.sub_fields[0].type_):
#                 return getattr(self, name)
#         raise TypeError(cls)
# 
#     def __contains__(self, item):
#         """Return :obj:`True` if `item` is in the StructureMessage."""
#         for field, field_info in direct_fields(self.__class__).items():
#             if isinstance(item, get_args(field_info.outer_type_)[1]):
#                 return item in getattr(self, field).values()
#         raise TypeError(f"StructureMessage has no collection of {type(item)}")
# 
#     def __repr__(self):
#         """String representation."""
#         lines = [super().__repr__()]
# 
#         # StructureMessage contents
#         for attr in self.__dict__.values():
#             if isinstance(attr, DictLike) and attr:
#                 lines.append(summarize_dictlike(attr))
# 
#         return "\n  ".join(lines)
# 
# Path: pandasdmx/writer/protobuf.py
# def write(obj, *args, **kwargs):
#     """Convert an SDMX *obj* to protobuf string."""
#     return _write(obj, *args, **kwargs).SerializeToString()


import logging
import pytest
from pandasdmx.message import StructureMessage
from pandasdmx.writer.protobuf import write as to_protobuf




@pytest.mark.xfail(raises=RuntimeError, match="sdmx.format.protobuf_pb2 missing")
def test_codelist(caplog, codelist):
    msg = StructureMessage()
    msg.codelist[codelist.id] = codelist

    caplog.set_level(logging.ERROR)


# Path: pandasdmx/message.py
# class StructureMessage(Message):
#     #: Collection of :class:`.Categorisation`.
#     categorisation: DictLike[str, model.Categorisation] = dictlike_field()
#     #: Collection of :class:`.CategoryScheme`.
#     category_scheme: DictLike[str, model.CategoryScheme] = dictlike_field()
#     #: Collection of :class:`.Codelist`.
#     codelist: DictLike[str, model.Codelist] = dictlike_field()
#     #: Collection of :class:`.ConceptScheme`.
#     concept_scheme: DictLike[str, model.ConceptScheme] = dictlike_field()
#     #: Collection of :class:`.ContentConstraint`.
#     constraint: DictLike[str, model.ContentConstraint] = dictlike_field()
#     #: Collection of :class:`.DataflowDefinition`.
#     dataflow: DictLike[str, model.DataflowDefinition] = dictlike_field()
#     #: Collection of :class:`.DataStructureDefinition`.
#     structure: DictLike[str, model.DataStructureDefinition] = dictlike_field()
#     #: Collection of :class:`.AgencyScheme`.
#     organisation_scheme: DictLike[str, model.AgencyScheme] = dictlike_field()
#     #: Collection of :class:`.ProvisionAgreement`.
#     provisionagreement: DictLike[str, model.ProvisionAgreement] = dictlike_field()
# 
#     def compare(self, other, strict=True):
#         """Return :obj:`True` if `self` is the same as `other`.
# 
#         Two StructureMessages compare equal if :meth:`.DictLike.compare` is :obj:`True`
#         for each of the object collection attributes.
# 
#         Parameters
#         ----------
#         strict : bool, optional
#             Passed to :meth:`.DictLike.compare`.
#         """
#         return super().compare(other, strict) and all(
#             getattr(self, f).compare(getattr(other, f), strict)
#             for f in direct_fields(self.__class__).keys()
#         )
# 
#     def add(self, obj: model.IdentifiableArtefact):
#         """Add `obj` to the StructureMessage."""
#         for field, field_info in direct_fields(self.__class__).items():
#             # NB for some reason mypy complains here, but not in __contains__(), below
#             if isinstance(
#                 obj, get_args(field_info.outer_type_)[1],  # type: ignore [attr-defined]
#             ):
#                 getattr(self, field)[obj.id] = obj
#                 return
#         raise TypeError(type(obj))
# 
#     def get(
#         self, obj_or_id: Union[str, model.IdentifiableArtefact]
#     ) -> Optional[model.IdentifiableArtefact]:
#         """Retrieve `obj_or_id` from the StructureMessage.
# 
#         Parameters
#         ----------
#         obj_or_id : str or .IdentifiableArtefact
#             If an IdentifiableArtefact, return an object of the same class and
#             :attr:`~.IdentifiableArtefact.id`; if :class:`str`, an object with this ID.
# 
#         Returns
#         -------
#         .IdentifiableArtefact
#             with the given ID and possibly class.
#         None
#             if there is no match.
# 
#         Raises
#         ------
#         ValueError
#             if `obj_or_id` is a string and there are ≥2 objects (of different classes)
#             with the same ID.
#         """
#         id = (
#             obj_or_id.id
#             if isinstance(obj_or_id, model.IdentifiableArtefact)
#             else obj_or_id
#         )
# 
#         candidates: List[model.IdentifiableArtefact] = list(
#             filter(
#                 None,
#                 map(
#                     lambda f: getattr(self, f).get(id),
#                     direct_fields(self.__class__).keys(),
#                 ),
#             )
#         )
# 
#         if len(candidates) > 1:
#             raise ValueError(f"ambiguous; {repr(obj_or_id)} matches {repr(candidates)}")
# 
#         return candidates[0] if len(candidates) == 1 else None
# 
#     def objects(self, cls):
#         """Get a reference to the attribute for objects of type `cls`.
# 
#         For example, if `cls` is the class :class:`DataStructureDefinition` (not an
#         instance), return a reference to :attr:`structure`.
#         """
#         for name, info in direct_fields(self.__class__).items():
#             if issubclass(cls, info.sub_fields[0].type_):
#                 return getattr(self, name)
#         raise TypeError(cls)
# 
#     def __contains__(self, item):
#         """Return :obj:`True` if `item` is in the StructureMessage."""
#         for field, field_info in direct_fields(self.__class__).items():
#             if isinstance(item, get_args(field_info.outer_type_)[1]):
#                 return item in getattr(self, field).values()
#         raise TypeError(f"StructureMessage has no collection of {type(item)}")
# 
#     def __repr__(self):
#         """String representation."""
#         lines = [super().__repr__()]
# 
#         # StructureMessage contents
#         for attr in self.__dict__.values():
#             if isinstance(attr, DictLike) and attr:
#                 lines.append(summarize_dictlike(attr))
# 
#         return "\n  ".join(lines)
# 
# Path: pandasdmx/writer/protobuf.py
# def write(obj, *args, **kwargs):
#     """Convert an SDMX *obj* to protobuf string."""
#     return _write(obj, *args, **kwargs).SerializeToString()


# Path: pandasdmx/tests/writer/test_protobuf.py
import logging
import pytest
from pandasdmx.message import StructureMessage
from pandasdmx.writer.protobuf import write as to_protobuf





@pytest.mark.xfail(raises=RuntimeError, match="sdmx.format.protobuf_pb2 missing")
def test_codelist(caplog, codelist):
    msg = StructureMessage()
    msg.codelist[codelist.id] = codelist

    caplog.set_level(logging.ERROR)


    result = to_protobuf(msg)