Skip to main content

A python interface to interacting with p4 as a soft dependency

Project description

Overview

Xpf is an interface to perforce which offers the following benefits:

  • Pure python, no compiled dependencies (allow for use in Python 2, Python 3, Max, Maya & Motion Builder etc)

  • Failsafe calls - this module will not raise errors if the perforce server is in-accessible.

  • PyPi distribution making it easier for sharing tools with outsourcers

Installation

Either download and place somewhere in your PYTHONPATH or install via pypi:

pip install xpf

Why not P4Python

Perforce offers its own p4Python module which is a well established and stable library.

The downside to P4Python is that its a compiled library and therefore requires different distributions if you're jumping between Python 2.x and Python 3.x

This is further exasperated when wanting to utilise perforce integrations into tools built within embedded interpreters such as Autodesk Maya/Max/Motionbuilder which are all compiled against different compiler versions than the native python distributions.

The other benefit xpf brings is that its has a soft requirement on perforce. Its common place to want to embed perforce support into tools within applications such as Max/Maya but it opens the challenge of allowing your tools to still operate outside of your studio environments when the Perforce server is in-accessible.

Xpf resolves this by ensuring all the perforce calls can return default variable types in circumstances where the Perforce server is unreachable. This allows for tools to operate outside the main studio environment, and is made easier by xpf being freely accessible on PyPi.

Xpf Direct

The library tries to make it easy to use for those that are used to utilising P4Python or the perforce command line. With that in mind you can utilise the the xpf.direct module which mimics the types of calls and interface of P4Python.

In this regard you're given access to functions for each perforce command and are able to pass in any arguments you want to give. As per P4Python conventions you will be returned a list of dictionaries representing the results.

Some examples of this would be:

import xpf

# -- Sync to the head revision of a directory
xpf.direct.sync(
    [
        '/usr/my_files/...'
    ]
)

# -- Force sync, passing the usual perforce argument switches, but
# -- define the client
xpf.direct.sync(
    [
        '/usr/my_files/...'
    ],
    '-f',
    client='my_client_name',
)

As well as the defined functions (which are auto-generated) there is also a more generic run function which you can utilise directly:

import xpf

# -- Sync to the head revision of a directory
result = xpf.direct.run(
    'describe',
    13569,                  # -- Change list to describe
    'Os',                   # -- Shorten output by excluding client workspace data
    'Rc',                   # -- Limit output to files mapped into the current workspace.
)

Using xpf.direct should feel very familiar to anyone who has utilised P4Python or the perforce commandline.

Xpf Assist

Working at the xpf.direct level makes a lot of sense in a lot of situations, however there are various circumstances which call for multiple queries to be carried out in order to answer slightly higher level questions.

Examples of these might be to add a file to a changelist regardless of whether its an add or edit operation. Another example might be where you want to manage the changelist descriptions a little easier.

The xpf.assist module aims to give higher level functionality whereby the function in question will carry out multiple calls and wrangle data to solve a particular request.

Examples of these are:

import xpf

# -- Given a chnagelist description, find the most likely changelist
# -- number for the current user. In this case, if that changelist
# -- does not exist it will be created for you
result = xpf.assist.get_changelist('My change description')

The following example exposes a method of submitting which forces all files being submitted to be added to a changelist with the supplied description and submitted together:

import xpf

xpf.assist.submit_files(
    [
        '/usr/my_files/...'
    ],
    description='My submission description',
)

Xpf Variables

Xpf works at a module level. It is not class based and it wraps the perforce command line. With this in mind it has some variables which are considered global, which are queried for on the first run (based on p4 set) but can be altered by you.

import xpf

# -- Get the host
host = xpf.variables.get_host()

# -- Set the host to something specific
xpf.variables.set_host(host)

Variables which can be retrieved and set in this way include:

* host
* client
* user
* port (server)
* timeout

A special variable which can be turned on/off is the debugging variable. When debugging is turned on xpf will print ever command line its about to process in the final format its constructed in. This is particularly useful if you're getting a result you do not expect and want to recreate the steps using the commandline.

To enable this option you do:

import xpf

xpf.variables.set_debug(True)

Failsafes

One of the big advantages of xpf is that includes in-built failsafe mechanisms to protect functionality whenever the server is in-accessible. During the first xpf call (regardless of whether that is through xpf.direct or xpf.assist) a p4 info query is run. If this timesout then the xpf variable is set to mark the server as inaccessible.

When a server is inaccessible all functions will return a default value which is defined by their failsafe decorator. This allows your code to continue without having to handle server failure directly.

In many situations when calling functions within xpf.direct they will return an empty list upon server failure - this is because their functions usually return a list. With that in mind, whilst you dont have to handle server failure you should handle being given empty data of the correct (expected) type.

A good example of this would be:

description = xpf.direct.describe(13569)

if not description:
    pass

...

In the example above we do have to handle not being given a description but we do not have to handle unexpected exceptions beacuse of an inaccessible perforce server.

Fundamentally this means you can safely embed an xpf dependency in your tool to give a rich user experience knowing that the tool will work even if its taken off-site.

Timeouts

Xpf offers the ability to define a timeout on all perforce queries. By default this timeout is exposed through xpf.set_timeout(value) and is defaulted to one second. If your server is particularly slow you can use that call to increase the global timeout.

Alternatively, you can set the timeout on a per-call basis too. This is particularly useful when you know your call will take a longer than expected time. This is done with the timeout argument as shown here:

import xpf

xpf.direct.info(timeout=10)

Marshalling

By default all queries run through xpf are marshaled, and therefore return pythonic objects. If you want raw output (strings) rather than lists of dictionaries you can set the marshaling to false on a per call basis as shown here:

string_dump = xpf.direct.run('set', marshal=False)  # -- (Equivalent to p4 set)

Forms

Forms are used in perforce to deliver multiple pieces of user input. When running perforce through the commandline this typically pops open a text editor - which is not particularly useful when interacting with perforce via a python library.

Therefore all forms that are requested by a particular p4 command can be given in the form of a dictionary. This is shown here:

import xpf

result = xpf.direct.changelist(
    '-i',
    form={
        'Change': 'new',
        'Status': 'new',
        'Description': 'My New Changelist Description',
    },
)

Compatibility

Xpf has been tested under Python 2.7 and Python 3.7 on Windows and Ubuntu.

Note: This module utilises the p4 set environment variables and expects at least P4PORT, P4USER and P4CLIENT to be defined.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xpf-1.0.1.tar.gz (16.9 kB view hashes)

Uploaded source

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page