Programming with P4Python

P4Python provides an object-oriented interface to Perforce 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 Perforce 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 Perforce 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()
  # Convert client spec into 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

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 Perforce using ticket-based authentication

On some servers, users might need to log in to Perforce before issuing commands. The following example illustrates login using Perforce 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 Perforce 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 )