Object Dumper Class

object dumper class

The object dumper posted in sgmoore's link:

//Copyright (C) Microsoft Corporation.  All rights reserved.

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

// See the ReadMe.html for additional information
public class ObjectDumper {

public static void Write(object element)
{
Write(element, 0);
}

public static void Write(object element, int depth)
{
Write(element, depth, Console.Out);
}

public static void Write(object element, int depth, TextWriter log)
{
ObjectDumper dumper = new ObjectDumper(depth);
dumper.writer = log;
dumper.WriteObject(null, element);
}

TextWriter writer;
int pos;
int level;
int depth;

private ObjectDumper(int depth)
{
this.depth = depth;
}

private void Write(string s)
{
if (s != null) {
writer.Write(s);
pos += s.Length;
}
}

private void WriteIndent()
{
for (int i = 0; i < level; i++) writer.Write(" ");
}

private void WriteLine()
{
writer.WriteLine();
pos = 0;
}

private void WriteTab()
{
Write(" ");
while (pos % 8 != 0) Write(" ");
}

private void WriteObject(string prefix, object element)
{
if (element == null || element is ValueType || element is string) {
WriteIndent();
Write(prefix);
WriteValue(element);
WriteLine();
}
else {
IEnumerable enumerableElement = element as IEnumerable;
if (enumerableElement != null) {
foreach (object item in enumerableElement) {
if (item is IEnumerable && !(item is string)) {
WriteIndent();
Write(prefix);
Write("...");
WriteLine();
if (level < depth) {
level++;
WriteObject(prefix, item);
level--;
}
}
else {
WriteObject(prefix, item);
}
}
}
else {
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
WriteIndent();
Write(prefix);
bool propWritten = false;
foreach (MemberInfo m in members) {
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null) {
if (propWritten) {
WriteTab();
}
else {
propWritten = true;
}
Write(m.Name);
Write("=");
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string)) {
WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null));
}
else {
if (typeof(IEnumerable).IsAssignableFrom(t)) {
Write("...");
}
else {
Write("{ }");
}
}
}
}
if (propWritten) WriteLine();
if (level < depth) {
foreach (MemberInfo m in members) {
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null) {
Type t = f != null ? f.FieldType : p.PropertyType;
if (!(t.IsValueType || t == typeof(string))) {
object value = f != null ? f.GetValue(element) : p.GetValue(element, null);
if (value != null) {
level++;
WriteObject(m.Name + ": ", value);
level--;
}
}
}
}
}
}
}
}

private void WriteValue(object o)
{
if (o == null) {
Write("null");
}
else if (o is DateTime) {
Write(((DateTime)o).ToShortDateString());
}
else if (o is ValueType || o is string) {
Write(o.ToString());
}
else if (o is IEnumerable) {
Write("...");
}
else {
Write("{ }");
}
}
}

2015 Update

YAML also serves this purpose quite well, this is how it can be done with YamlDotNet

install-package YamlDotNet

    private static void DumpAsYaml(object o)
{
var stringBuilder = new StringBuilder();
var serializer = new Serializer();
serializer.Serialize(new IndentedTextWriter(new StringWriter(stringBuilder)), o);
Console.WriteLine(stringBuilder);
}

What is the best way to dump entire objects to a log in C#?

You could base something on the ObjectDumper code that ships with the Linq samples.

Have also a look at the answer of this related question to get a sample.

Dumping a java object's properties

You could try XStream.

XStream xstream = new XStream(new Sun14ReflectionProvider(
new FieldDictionary(new ImmutableFieldKeySorter())),
new DomDriver("utf-8"));
System.out.println(xstream.toXML(new Outer()));

prints out:

<foo.ToString_-Outer>
<intValue>5</intValue>
<innerValue>
<stringValue>foo</stringValue>
</innerValue>
</foo.ToString_-Outer>

You could also output in JSON

And be careful of circular references ;)

Pickle Dump to save an object within the class

You can pass self instead of obj. In other words:

def save(self, file_handler):
pickle.dump(self, file_handler)

The self points to the instance of that class. So what you basically do is calling pickle.dump and passing the instance to it together with the file_handler argument.

How to dump user defined python objects to json file? By Objects I mean actual objects and not their attributes

Use pickle.

It will not be human readable and not in json format. But this module is intended to store Python objects and load it back again in future.

See more this for comparison with json module.

dump an python object as yaml file

You need to implement __repr__ for the class. You could just use your __str__ as __repr__.

YAML - Dumping a nested object without types/tags

Although the words "correct YAML" are not really accurate, and would be better phrased as
"YAML output looking like you want it, except for the tag information", this fortunately gives some
information on how you want your YAML to look, as there are an infinite number of ways to dump objects.

If you dump an object using ruamel.yaml:

import sys
import ruamel.yaml

class MyObject:
def __init__(self, a, b):
self.a = a
self.b = b
self.c = [a, b]

data = dict(x=MyObject(42, -1))

yaml = ruamel.yaml.YAML(typ='unsafe')
yaml.dump(data, sys.stdout)

this gives:

x: !!python/object:__main__.MyObject
a: 42
b: -1
c: [42, -1]

You have a tag !!python/object:__main__.MyObject (yours might differ depending on where the
class is defined, etc.) and each of the attributes of the class are dumped as keys of a mapping.

There are multiple ways on how to get rid of the tag in that dump:

Registering classes

Add a classmethod named to_yaml(), to each of your classes and
register those classes. You have to do this for each of your classes,
but doing so allows you to use the safe-dumper. An example on how to
do this can be found in the
documentation

Post-process

It is fairly easy to postprocess the output and remove the tags, which for objects always occur on the line
before the mapping, and you can delete from !!python until the end-of-line

def strip_python_tags(s):
result = []
for line in s.splitlines():
idx = line.find("!!python/")
if idx > -1:
line = line[:idx]
result.append(line)
return '\n'.join(result)

yaml.encoding = None
yaml.dump(data, sys.stdout, transform=strip_python_tags)

and that gives:

x: 
a: 42
b: -1
c: [42, -1]

As achors are dumped before the tag, this "stripping from !!python
until end-of-the line", also works when you dump object that have
multiple references.

Change the dumper

You can also change the unsafe dumper routine for mappings to
recognise the tag used for objects and change the tag to the "normal"
one for dict/mapping (for which normally a tag is not output )

yaml.representer.org_represent_mapping = yaml.representer.represent_mapping

def my_represent_mapping(tag, mapping, flow_style=None):
if tag.startswith("tag:yaml.org,2002:python/object"):
tag = u'tag:yaml.org,2002:map'
return yaml.representer.org_represent_mapping(tag, mapping, flow_style=flow_style)

yaml.representer.represent_mapping = my_represent_mapping

yaml.dump(data, sys.stdout)

and that gives once more:

x:
a: 42
b: -1
c: [42, -1]

These last two methods work for all instances of all Python classes that you define without extra work.



Related Topics



Leave a reply



Submit