Data::Printer - colored & full-featured pretty print of Perl data structures and objects
Want to see what's inside a variable in a complete, colored and human-friendly way?
use DDP; # same as 'use Data::Printer'
p $some_var;
p $some_var, as => "This label will be printed too!";
# no need to use '\' before arrays or hashes!
p @array;
p %hash;
# for anonymous array/hash references, use postderef (on perl 5.24 or later):
p [ $one, $two, $three ]->@*;
p { foo => $foo, bar => $bar }->%*;
# or deref the anonymous ref:
p @{[ $one, $two, $three ]};
p %{{ foo => $foo, bar => $bar }};
# or put '&' in front of the call:
&p( [ $one, $two, $three ] );
&p( { foo => $foo, bar => $bar } );
The snippets above will print the contents of the chosen variables to STDERR
on your terminal, with colors and a few extra features to help you debug
your code.
If you wish to grab the output and handle it yourself, call np() :
my $dump = np $var;
die "this is what happened: " . np %data;
The np() function is the same as p() but will return the string
containing the dump. By default it has no colors, but you can change that
easily too.
That's pretty much it :)
Data::Printer is fully customizable, even
on a per-module basis! Once you figure out your own preferences, create a
.dataprinter configuration file
for yourself (or one for each project) and Data::Printer will automatically
use it!
Here's what Data::Printer offers Perl developers, out of the box:
The ever-popular Data::Dumper is a fantastic tool, meant to stringify
data structures in a way they are suitable for being ``eval'''ed back in.
The thing is, a lot of people keep using it (and similar ones, like
Data::Dump) to print data structures and objects on screen for inspection
and debugging, and while you can use those modules for that, it doesn't
mean you should.
This is where Data::Printer comes in. It is meant to do one thing and one
thing only:
format Perl variables and objects to be inspected by a human >
If you want to serialize/store/restore Perl data structures, this module
will NOT help you. Try Storable, Data::Dumper, JSON, or whatever. CPAN is
full of such solutions!
Whenever you type use Data::Printer or use DDP , we export two functions
to your namespace:
This function pretty-prints the contents of whatever variable to STDERR
(by default), and will use colors by default if your terminal supports it.
p @some_array;
p %some_hash;
p $scalar_or_ref;
Note that anonymous structures will only work if you postderef them:
p [$foo, $bar, $baz]->@*;
you may also deref it manually:
p %{{ foo => $foo }};
or prefix p() with & :
&p( [$foo, $bar, $baz] ); # & (note mandatory parenthesis)
You can pass custom options that will work only on that particular call:
p @var, as => "some label", colorized => 0;
p %var, show_memsize => 1;
By default, p() prints to STDERR and returns the same variable being
dumped. This lets you quickly wrap variables with p() without worrying
about changing return values. It means that if you change this:
sub foo { my $x = shift + 13; $x }
to this:
sub foo { my $x = shift + 13; p($x) }
The function will still return $x after printing the contents. This form
of handling data even allows method chaining, so if you want to inspect what's
going on in the middle of this:
$object->foo->bar->baz;
You can just add DDP::p anywhere:
$object->foo->DDP::p->bar->baz; # what happens to $object after ->foo?
Check out the customization quick reference
section below for all available options, including changing the return type,
output target and a lot more.
The np() function behaves exactly like p() except it always returns
the string containing the dump (thus ignoring any setting regarding dump
mode or destination), and contains no colors by default. In fact, the only
way to force a colored np() is to pass colored => 1 as an argument
to each call. It is meant to provide an easy way to fetch the dump and send
it to some unsupported target, or appended to some other text (like part of
a log message).
There are 3 possible ways to customize Data::Printer:
1. [RECOMMENDED] Creating a .dataprinter file either on your home
directory or your project's base directory, or both, or wherever you set
the DATAPRINTERRC environment variable to.
2. Setting custom properties on module load. This will override any
setting from your config file on the namespace (package/module) it was called:
use DDP max_depth => 2, deparse => 1;
3. Setting custom properties on the actual call to p() or np() . This
overrides all other settings:
p $var, show_tainted => 1, indent => 2;
The most powerful way to customize Data::Printer is to have a .dataprinter
file in your home directory or your project's root directory. The format
is super simple and can be understood in the example below:
# global settings (note that only full line comments are accepted)
max_depth = 1
theme = Monokai
class.stringify = 0
# use quotes if you want spaces to be significant:
hash_separator = " => "
# You can set rules that apply only to a specific
# caller module (in this case, MyApp::Some::Module):
[MyApp::Some::Module]
max_depth = 2
class.expand = 0
escape_chars = nonlatin1
[MyApp::Other::Module]
multiline = 0
output = /var/log/myapp/debug.data
Note that if you set custom properties as arguments to p() or np() , you
should group suboptions as a hashref. So while the .dataprinter file has
``class.expand = 0 '' and ``class.inherited = none '', the equivalent
code is ``class => { expand => 0, inherited => 'none' } ''.
Below are (almost) all available properties and their (hopefully sane)
default values. See the Data::Printer::Object manpage for further information on
each of them:
# scalar options
show_tainted = 1
show_unicode = 1
show_lvalue = 1
print_escapes = 0
scalar_quotes = "
escape_chars = none
string_max = 4096
string_preserve = begin
string_overflow = '(...skipping __SKIPPED__ chars...)'
unicode_charnames = 0
# array options
array_max = 100
array_preserve = begin
array_overflow = '(...skipping __SKIPPED__ items...)'
index = 1
# hash options
hash_max = 100
hash_preserve = begin
hash_overflow = '(...skipping __SKIPPED__ keys...)'
hash_separator = ' '
align_hash = 1
sort_keys = 1
quote_keys = auto
# general options
name = var
return_value = pass
output = stderr
use_prototypes = 1
indent = 4
show_readonly = 1
show_tied = 1
show_dualvar = lax
show_weak = 1
show_refcount = 0
show_memsize = 0
memsize_unit = auto
separator = ,
end_separator = 0
caller_info = 0
caller_message = 'Printing in line __LINE__ of __FILENAME__'
max_depth = 0
deparse = 0
alias = p
warnings = 1
# colorization (see Colors & Themes below)
colored = auto
theme = Material
# object output
class_method = _data_printer
class.parents = 1
class.linear_isa = auto
class.universal = 1
class.expand = 1
class.stringify = 1
class.show_reftype = 0
class.show_overloads = 1
class.show_methods = all
class.sort_methods = 1
class.inherited = none
class.format_inheritance = string
class.parent_filters = 1
class.internals = 1
Data::Printer lets you set custom colors for pretty much every part of the
content being printed. For example, if you want numbers to be shown in
bright green, just put colors.number = #00ff00 on your configuration
file.
See the Data::Printer::Theme manpage for the full list of labels, ways to represent
and customize colors, and even how to group them in your own custom theme.
The colorization is set by the colored property. It can be set to 0
(never colorize), 1 (always colorize) or 'auto' (the default), which will
colorize p() only when there is no ANSI_COLORS_DISABLED environment
variable, the output is going to the terminal (STDOUT or STDERR) and your
terminal actually supports colors.
You may bundle your settings and filters into a profile module.
It works like a configuration file but gives you the power and flexibility
to use Perl code to find out what to print and how to print. It also lets
you use CPAN to store your preferred settings and install them into your
projects just like a regular dependency.
use DDP profile => 'ProfileName';
See the Data::Printer::Profile manpage for all the ways to load a profile, a list
of available profiles and how to make one yourself.
Data::Printer works by passing your variable to a different set of filters,
depending on whether it's a scalar, a hash, an array, an object, etc. It
comes bundled with filters for all native data types (always enabled, but
overwritable), including a generic object filter that pretty-prints regular
and Moo(se) objects and is even aware of Role::Tiny.
Data::Printer also comes with filter bundles that can be quickly activated
to make it easier to debug binary data
and many popular CPAN modules that handle
date and time,
databases (yes, even DBIx::Class),
message digests like MD5 and SHA1, and
JSON and Web content like HTTP requests and
responses.
So much so we recommend everyone to activate all bundled filters by putting
the following line on your .dataprinter file:
filters = ContentType, DateTime, DB, Digest, Web
Creating your custom filters is very easy, and
you're encouraged to upload them to CPAN. There are many options available
under the Data::Printer::Filter::* namespace. Check
the Data::Printer::Filter manpage for more information!
The default object filter will first check if the class implements a sub
called '_data_printer() ' (or whatever you set the ``class_method'' option
to in your settings). If so, Data::Printer will use it to get the string to
print instead of making a regular class dump.
This means you could have the following in one of your classes:
sub _data_printer {
my ($self, $ddp) = @_;
return 'Hey, no peeking! But foo contains ' . $self->foo;
}
Notice that you can do this without adding Data::Printer as a dependency >
to your project! Just write your sub and it will be called with the object to
be printed and a $ddp object ready for you. See
Data::Printer::Object
for how to use it to pretty-print your data.
Finally, if your object implements string overload or provides a method called
``to_string'', ``as_string'' or ``stringify'', Data::Printer will use it. To disable
this behaviour, set class.stringify = 0 on your .dataprinter
file, or call p() with class => { stringify => 0 } .
Loading a filter for that particular class will of course override these settings.
You can't pass more than one variable at a time.
p $foo, $bar; # wrong
p $foo; p $bar; # right
You can't use it in variable declarations (it will most likely not do what
you want):
p my @array = qw(a b c d); # wrong
my @array = qw(a b c d); p @array; # right
If you pass a nonexistant key/index to DDP using prototypes, they
will trigger autovivification:
use DDP;
my %foo;
p $foo{bar}; # undef, but will create the 'bar' key (with undef)
my @x;
p $x[5]; # undef, but will initialize the array with 5 elements (all undef)
Slices (both array and hash) must be coerced into actual arrays (or hashes)
to properly shown. So if you want to print a slice, instead of doing something
like this:
p @somevar[1..10]; # WRONG! DON'T DO THIS!
try one of those:
my @x = @somevar[1..10]; p @x; # works!
p [ @somevar[1..0] ]->@*; # also works!
p @{[@somevar[1..0]]}; # this works too!!
Finally, as mentioned before, you cannot pass anonymous references on the
default mode of use_prototypes = 1 :
p { foo => 1 }; # wrong!
p %{{ foo => 1 }}; # right
p { foo => 1 }->%*; # right on perl 5.24+
&p( { foo => 1 } ); # right, but requires the parenthesis
sub pp { p @_ }; # wrapping it also lets you use anonymous data.
use DDP use_prototypes => 0;
p { foo => 1 }; # works, but now p(@foo) will fail, you must always pass a ref,
# e.g. p(\@foo)
While we make a genuine effort not to break anything on new releases,
sometimes we do. To make things easier for people migrating their
code, we have aggregated here a list of all incompatible changes since ever:
- 1.00 - some defaults changed!
Because we added a bunch of new features (including color themes), you may
notice some difference on the default output of Data::Printer. Hopefully it's
for the best.
- 1.00 - new .dataprinter file format.
I<< This should only affect you if you have a C<.dataprinter> file. >>
The change was required to avoid calling C on potentially tainted/unknown
code. It also provided a much cleaner interface.
- 1.00 - new way of creating external filters.
This only affects you if you write or use external filters. >
Previously, the sub in your
filters call would get the reference to be
parsed and a properties hash. The properties hash has been replaced with a
the Data::Printer::Object manpage instance, providing much more power and flexibility.
Because of that, the filter call does not export p() /np() anymore,
replaced by methods in Data::Printer::Object.1.00 - new way of creating external filters.
I<< This only affects you if you write or use external filters. >>
Previously, the sub in your C call would get the reference to be
parsed and a properties hash. The properties hash has been replaced with a
L instance, providing much more power and flexibility.
Because of that, the filter call does not export C/C anymore,
replaced by methods in Data::Printer::Object.
- 1.00 - new way to call filters.
I<< This affects you if you load your own inline filters >>.
The fix is quick and Data::Printer will generate a warning explaining how
to do it. Basically, C<< filters => { ... } >> became
C<< filters => [{ ... }] >> and you must replace C<< -external => [1,2] >>
with C<< filters => [1, 2] >>, or C<< filters => [1, 2, {...}] >> if you
also have inline filters. This allowed us much more power and flexibility
with filters, and hopefully also makes things clearer.
- 0.36 -
p() 's default return value changed from 'dump' to 'pass'.
This was a very important change to ensure chained calls and to prevent
weird side-effects when p() is the last statement in a sub.
Read the full discussion.0.36 - p()'s default return value changed from 'dump' to 'pass'.
This was a very important change to ensure chained calls and to prevent
weird side-effects when C is the last statement in a sub.
L<< Read the full discussion|https://github.com/garu/Data-Printer/issues/16 >>.
Any undocumented change was probably unintended. If you bump into one,
please file an issue on Github!
Using p() in some/all of your loaded modules
(contributed by Matt S. Trout (mst)) >
While debugging your software, you may want to use Data::Printer in some or
all loaded modules and not bother having to load it in each and every one of
them. To do this, in any module loaded by myapp.pl , simply write:
::p @myvar; # note the '::' in front of p()
Then call your program like:
perl -MDDP myapp.pl
This also has the advantage that if you leave one p() call in by accident,
it will trigger a compile-time failure without the -M, making it easier to
spot :)
If you really want to have p() imported into your loaded modules, use the
next tip instead.
Adding p() to all your loaded modules
(contributed by Árpád Szász) >
If you wish to automatically add Data::Printer's p() function to
every loaded module in you app, you can do something like this to
your main program:
BEGIN {
{
no strict 'refs';
require Data::Printer;
my $alias = 'p';
foreach my $package ( keys %main:: ) {
if ( $package =~ m/::$/ ) {
*{ $package . $alias } = \&Data::Printer::p;
}
}
}
}
WARNING This will override all locally defined subroutines/methods that
are named p , if they exist, in every loaded module. If you already
have a subroutine named 'p() ', be sure to change $alias to
something custom.
If you rather avoid namespace manipulation altogether, use the previous
tip instead.
(contributed by Árpád Szász and Marcel Grünauer (hanekomu)) >
With the DB::Pluggable manpage, you can easily set the perl debugger to use
Data::Printer to print variable information, replacing the debugger's
standard p() function. All you have to do is add these lines to
your .perldb file:
use DB::Pluggable;
DB::Pluggable->run_with_config( \'[DataPrinter]' ); # note the '\'
Then call the perl debugger as you normally would:
perl -d myapp.pl
Now Data::Printer's p() command will be used instead of the debugger's!
See perldebug for more information on how to use the perl debugger, and
the DB::Pluggable manpage for extra functionality and other plugins.
If you can't or don't want to use DB::Pluggable, or simply want to keep
the debugger's p() function and add an extended version using
Data::Printer (let's call it px() for instance), you can add these
lines to your .perldb file instead:
$DB::alias{px} = 's/px/DB::px/';
sub px {
my $expr = shift;
require Data::Printer;
print Data::Printer::p($expr);
}
Now, inside the Perl debugger, you can pass as reference to px expressions
to be dumped using Data::Printer.
Some people really enjoy using a REPL shell to quickly try Perl code. One
of the most popular ones out there is the Devel::REPL manpage. If you use it, now
you can also see its output with Data::Printer!
Just install the Devel::REPL::Plugin::DataPrinter manpage and add the following
line to your re.pl configuration file (usually ``.re.pl/repl.rc'' in your
home dir):
load_plugin('DataPrinter');
The next time you run re.pl , it should dump all your REPL using
Data::Printer!
To turn Data::Printer's output into HTML, you can do something like:
use HTML::FromANSI;
use Data::Printer;
my $html_output = ansi2html( np($object, colored => 1) );
In the example above, the $html_output variable contains the
HTML escaped output of p($object) , so you can print it for
later inspection or render it (if it's a web app).
(contributed by Stephen Thirlwall (sdt)) >
If you use Template Toolkit and want to dump your variables using Data::Printer,
install the the Template::Plugin::DataPrinter manpage module and load it in your template:
[% USE DataPrinter %]
The provided methods match those of Template::Plugin::Dumper :
ansi-colored dump of the data structure in "myvar":
[% DataPrinter.dump( myvar ) %]
html-formatted, colored dump of the same data structure:
[% DataPrinter.dump_html( myvar ) %]
The module allows several customization options, even letting you load it as a
complete drop-in replacement for Template::Plugin::Dumper so you don't even have
to change your previous templates!
If you are porting your code to use Data::Printer instead of
Data::Dumper, you could replace:
use Data::Dumper;
with something like:
use Data::Printer;
sub Dumper { np @_, colored => 1 }
this sub will accept multiple variables just like Data::Dumper.
(contributed by Kevin McGrath (catlgrep)) >
If you want a really unified approach to easily flip between debugging
outputs, use the Any::Renderer manpage and its plugins,
like the Any::Renderer::Data::Printer manpage.
(contributed by Sergey Aleynikov (randir)) >
There are times where viewing the current state of a variable is not
enough, and you want/need to see a full stack trace of a function call.
The the Devel::PrettyTrace manpage module uses Data::Printer to provide you just
that. It exports a bt() function that pretty-prints detailed information
on each function in your stack, making it easier to spot any issues!
(contributed by Marcel Grünauer (hanekomu)) >
dip is a dynamic instrumentation framework for troubleshooting Perl
programs, similar to DTrace.
In a nutshell, dip lets you create probes for certain conditions
in your application that, once met, will perform a specific action. Since
it uses Aspect-oriented programming, it's very lightweight and you only
pay for what you use.
dip can be very useful since it allows you to debug your software
without changing a single line of your original code. And Data::Printer
comes bundled with it, so you can use the p() function to view your
data structures too!
# Print a stack trace every time the name is changed,
# except when reading from the database.
dip -e 'before { print longmess(np $_->{args}[1], colored => 1)
if $_->{args}[1] } call "MyObj::name" & !cflow("MyObj::read")' myapp.pl
You can check dip's own documentation for more information and options.
(contributed by Yanick Champoux (yanick)) >
The ``examples/try_me.pl'' file included in this distribution has a sample
dump with a complex data structure to let you quickly test color schemes.
As of 1.0.0 this module complies with Major.Minor.Revision versioning
scheme (SemVer), meaning backwards incompatible changes will trigger a new
major number, new features without any breaking changes trigger a new minor
number, and simple patches trigger a revision number.
Many thanks to everyone who helped design and develop this module with
patches, bug reports, wishlists, comments and tests. They are (alphabetically):
Adam Rosenstein, Alexandr Ciornii (chorny), Alexander Hartmaier (abraxxa),
Allan Whiteford, Anatoly (Snelius30), Andreas König (andk), Andy Bach,
Anthony DeRobertis, Árpád Szász, Athanasios Douitsis (aduitsis),
Baldur Kristinsson, Benct Philip Jonsson (bpj), brian d foy,
Chad Granum (exodist), Chris Prather (perigrin), Curtis Poe (Ovid),
David D Lowe (Flimm), David E. Condon (hhg7), David Golden (xdg),
David Precious (bigpresh), David Raab, David E. Wheeler (theory),
Damien Krotkine (dams), Denis Howe, dirk, Dotan Dimet, Eden Cardim (edenc),
Elliot Shank (elliotjs), Eugen Konkov (KES777), Fernando Corrêa (SmokeMachine),
Fitz Elliott, Florian (fschlich), Frew Schmidt (frew), GianniGi,
Graham Knop (haarg), Graham Todd, Gregory J. Oschwald, grr, Håkon Hægland,
Iaroslav O. Kosmina (darviarush), Ivan Bessarabov (bessarabv), J Mash,
James E. Keenan (jkeenan), Jarrod Funnell (Timbus), Jay Allen (jayallen),
Jay Hannah (jhannah), jcop, Jesse Luehrs (doy), Joel Berger (jberger),
John S. Anderson (genehack), Karen Etheridge (ether),
Kartik Thakore (kthakore), Kevin Dawson (bowtie), Kevin McGrath (catlgrep),
Kip Hampton (ubu), Londran, Marcel Grünauer (hanekomu),
Marco Masetti (grubert65), Mark Fowler (Trelane), Martin J. Evans,
Matt S. Trout (mst), Maxim Vuets, Michael Conrad, Mike Doherty (doherty),
Nicolas R (atoomic), Nigel Metheringham (nigelm), Nuba Princigalli (nuba),
Olaf Alders (oalders), Paul Evans (LeoNerd), Pedro Melo (melo),
Philippe Bruhat (BooK), Przemysław Wesołek (jest), Rebecca Turner (iarna),
Renato Cron (renatoCRON), Ricardo Signes (rjbs), Rob Hoelz (hoelzro),
Salve J. Nilsen (sjn), sawyer, Sebastian Willing (Sewi),
Sébastien Feugère (smonff), Sergey Aleynikov (randir), Slaven Rezić,
Stanislaw Pusep (syp), Stephen Thirlwall (sdt), sugyan, Tai Paul,
Tatsuhiko Miyagawa (miyagawa), Thomas Sibley (tsibley),
Tim Heaney (oylenshpeegul), Toby Inkster (tobyink), Torsten Raudssus (Getty),
Tokuhiro Matsuno (tokuhirom), trapd00r, Tsai Chung-Kuan,
Veesh Goldman (rabbiveesh), vividsnow, Wesley Dal`Col (blabos), y,
Yanick Champoux (yanick).
If I missed your name, please drop me a line!
Copyright (C) 2011-2021 Breno G. de Oliveira
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU.
SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO
YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|