MikeS MikeS - 2 months ago 20
Python Question

How to script p4 change changelist creation with marshalled python

I am trying to script creation of a new p4 changelist using the -G global option. This in combination with the -i command flag should allow me to pass in the changelist description through stdin as a marshaled python dictionary. Unfortunately, I can't find anywhere that p4 documents the format of this code.

If i look at an existing changelist using marshaled dictionaries I see this:

>>> argx=["/usr/bin/p4","-G", "change", "-o", "12345"]
>>> p=subprocess.Popen(argx, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> c=p.communicate()
>>> c
>>> marshal.loads(c[0])
{'Status': 'pending', 'code': 'stat', 'Description': 'test\t\n', 'Client': 'myclient', 'User': 'me', 'Date': '2015/02/18 18:36:34', 'Type': 'public', 'Change': '12345'}

So I tried creating one this way:

>>> x={'Change': 'new', 'Status': 'new', 'Description': "p4test"}
>>> y=marshal.dumps(x)
>>> args=["/usr/bin/p4","-G", "-d", "/tmp", "change", "-i"]
>>> p=subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> c=p.communicate(y)
>>> marshal.loads(c[0])
{'generic': 34, 'code': 'error', 'data': 'Invalid marshalled data supplied as input.\n', 'severity': 3}

(which is not very helpful)
But if I look at the un-unmarshalled return I see embedded in it:

('{s\x04\x00\x00\x00codes\x05\x00\x00\x00errors\x04\x00\x00\x00datas+\x00\x00\x00Invalid marshalled data supplied as input.\ns\x08\x00\x00\x00severityi\x03\x00\x00\x00s\x07\x00\x00\x00generici"\x00\x00\x000{s\x04\x00\x00\x00codes\x05\x00\x00\x00errors\x04\x00\x00\x00datas@\x00\x00\x00Error in change specification.\nMissing required field \'Change\'.\ns\x08\x00\x00\x00severityi\x03\x00\x00\x00s\x07\x00\x00\x00generici\x04\x00\x00\x000', '')

So 1. There is an incompatibility in the way the message is marshaled and unmarshaled, I'm not seeing the specific error message, but there is something wrong with my 'Change' field format,
or 2. The missing required field message is a red herring caused by a dirty buffer in p4's marshaling code.

Either way I can't figure out how to do this. Any suggestions? I'm trying to avoid having to introduce the p4 python API as it should be unnecessary considering how easy scripting most things (that don't involve editors) is in P4. I'm going to start investigating that now, however, as I've already done way too much trial an error with this.


I think you only have to change you dumps call to specify the version of the data format, like this:

y=marshal.dumps(x, 0)

See https://docs.python.org/2/library/marshal.html#marshal.version for details on the marshal module data format version.

The Perforce Knowledge Base has some information on this also, but you must know what to search for to find it! I stumbled on the same problem a few years ago and spent days to fix the problem.


When using "marshal.dump()" in Python 2.4 or later, you must specify version "0" of the dump format or P4 cannot understand the data that is being sent.

I just tested it and I can successfully create a new changelist with a manually-constructed dictionary passed as input.