Helix Core P4Python Developer Guide (2020.1)

Programming with P4Python

P4Python provides an object-oriented interface to Helix Core server that is intended to be intuitive for Python programmers. Data is loaded and returned in Python arrays and dictionaries. Each P4 object represents a connection to the Helix server.

When instantiated, the P4 instance is set up with the default environment settings just as the command line client p4, that is, using environment variables, the registry or user preferences (on Windows and OS X) and, if defined, the P4CONFIG file. The settings can be checked and changed before the connection to the server is established with the P4.connect() method. After your script connects, it can send multiple commands to the Helix server with the same P4 instance. After the script is finished, it should disconnect from the server by calling the P4.disconnect() method.

The following example illustrates the basic structure of a P4Python script. The example establishes a connection, issues a command, and tests for errors resulting from the command:

from P4 import P4,P4Exception    # Import the module
p4 = P4()                        # Create the P4 instance
p4.port = "1666"
p4.user = "fred"
p4.client = "fred-ws"            # Set some environment variables

try:                             # Catch exceptions with try/except
  p4.connect()                   # Connect to the Perforce server
  info = p4.run( "info" )        # Run "p4 info" (returns a dict)
  for key in info[0]:            # and display all key-value pairs
    print key, "=", info[0][key]
  p4.run( "edit", "file.txt" )   # Run "p4 edit file.txt"
  p4.disconnect()                # Disconnect from the server
except P4Exception:
  for e in p4.errors:            # Display errors
      print e

This example creates a client workspace from a template and syncs it:

from P4 import P4, P4Exception

template = "my-client-template"
client_root = "C:\work\my-root"
p4 = P4()

try:
  p4.connect()
  # Retrieve client spec as a Python dictionary
  client = p4.fetch_client( "-t", template )
  client._root = client_root
  p4.save_client( client )
  p4.run_sync()

except P4Exception:
  # If any errors occur, we'll jump in here. Just log them
  # and raise the exception up to the higher level
Note

When extending the P4 class, be sure to match the method signatures used in the default class. P4Python uses both variable length arguments (*args) and keyword arguments (**kwargs). Review the P4.py in the source bundle for specifics. Example code:

class MyP4(P4.P4):
def run(self, *args, **kargs):
P4.P4.run(self, *args, **kargs)

Using keyword arguments

All of the attributes that can be set for an active connection can also be provided as keyword arguments. This only works for a single command and you do not need to wrap the command in a with block. More than one keyword argument can be provided if required.

Examples

To disable tagged mode:

p4.run_counter('mycounter', tagged = False)

To provide an OutputHandler:

p4.run_files('//...', handler = MyOutputHandler() )

Submitting a Changelist

This example creates a changelist, modifies it and then submits it:

from P4 import P4

p4 = P4()
p4.connect()
change = p4.fetch_change()

# Files were opened elsewhere and we want to
# submit a subset that we already know about.

myfiles = ['//depot/some/path/file1.c', '//depot/some/path/file1.h']
change._description = "My changelist\nSubmitted from P4Python\n"
change._files = myfiles   # This attribute takes a Python list
p4.run_submit( change )

Logging into Helix server ticket-based authentication

On some servers, users might need to log in to Helix server before issuing commands. The following example illustrates login using Helix server tickets:

from P4 import P4

p4 = P4()
p4.user = "bruno"
p4.password = "my_password"
p4.connect()
p4.run_login()
opened = p4.run_opened()

...

Connecting to Helix server over SSL

Scripts written with P4Python use any existing P4TRUST file present in their operating environment (by default, .p4trust in the home directory of the user that runs the script).

If the fingerprint returned by the server fails to match the one installed in the P4TRUST file associated with the script’s run-time environment, your script will (and should!) fail to connect to the server.

Changing your password

You can use P4Python to change your password, as shown in the following example:

from P4 import P4

p4 = P4()
p4.user = "bruno"
p4.password = "MyOldPassword"
p4.connect()

p4.run_password( "MyOldPassword", MyNewPassword" )

# p4.password is automatically updated with the encoded password

Timestamp conversion

Timestamp information in P4Python is normally represented as seconds since Epoch (with the exception of P4.Revision). To convert this data to a more useful format, use the following procedure:

import datetime

...

myDate = datetime.datetime.utcfromtimestamp( int( timestampValue ) )

Working with comments in specs

As of P4Python 2012.3, comments in specs are preserved in the parse_<spectype>() and format_<spectype>() methods. This behavior can be circumvented by using parse_spec( '<spectype>', spec ) and format_spec( '<spectype>', spec ) instead of parse_<spectype>( spec ) and format_<spectype>( spec ). For example:

p4 = P4()
p4.connect()

...

# fetch a client spec in raw format, no formatting:
specform = p4.run( 'client', '-o', tagged=False )[0]

# convert the raw document into a spec
client1 = p4.parse_client( specform )

# comments are preserved in the spec as well
print( client1.comment )

# comments can be updated
client1.comment += "# ... and now for something completely different"

# the comment is prepended to the spec ready to be sent to the user
formatted1 = p4.format_client( client1 )

# or you can strip the comments
client2 = p4.parse_spec( 'client', specform )
formatted2 = p4.format_spec( 'client', specform )