Container

FileMaker container (binary) type.

Overview#Back to top

A FileMaker Container type stores binary data. A container may have multiple data streams; for example, files usually have a stream for a file name, images have a stream for image dimensions plus often an additional JPEG version of the image.

Streams are identified by type. Stream type is a four-character string from a known list that identifies the data type, for example:

  • FILE: file stream.

  • BMPf: image stream, BMP format.

  • JPEG: image stream, JPEG format.

  • snd : sound stream, old Macintosh System 7 format (note the trailing space, it is required).

Stream types are case-sensitive: BMPf must be entered exactly as it is.

There is no definite list of streams types, but you can always figure them out yourself: open PyFM Tools, go to the console, open the test table, insert the data you want to examine into Test::Global Container and read it back into the console:

>>> from filemaker import evaluate
>>> c = evaluate('Test::Global Container')

Now you can examine c, for example, get a list of keys with keys() method, read invidiual streams, etc.

Most stream store raw bytes, but two are special:

  • FNAM, file name stream, filemaker.Text.

  • SIZE, image dimensions stream, a tuple of two numbers.

For example, this is how you create a JPEG container with all the components:

>>> c = Container(JPEG='...', FNAM='image.jpeg', SIZE=(123, 456))

The SIZE stream is necessary if you want to view the image. Also, if FileMaker does not directly supports this format (for example, it doesn't support BMP), there must be a stream in a compatible format, usually JPEG. When you insert an image into FileMaker using the ‘Insert Picture’ command FileMaker adds all these necessities itself, but if you create containers programmatically, this becomes your responsibility.

Internally they're also stored as bytes and you can get these raw bytes with the bytes() method, if you're interested.

Strangely enough the FNAM stream does not come out as a plain string in any recognizable encoding. Here's what I get for abc.txt:

'\x00\x00\x00\x01\x04<36?\x00\x07;89t.".'

The first few bytes seem to encode the file reference type, then goes the size, but the rest is cryptic. Drop me a note if you manage to decipher it.

The FNAM stream stores the file name in FileMaker file reference format, that is it is not just abc.txt, it is something like file:abc.txt or, if you inserted it from disk, the full path to the file, sich as filewin:/C:/Users/Mikhail/Desktop/abc.txt. You don't have to read and parse it though; if you simply need the file name, you can get it by creating a new Text instance with the container as parameter:

>>> from filemaker import Container, Text
>>> c = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> str(Text(c))
'abc.txt'

Reference-only containers#Back to top

Reference-only containers are not containers, they actually store a text string. If your function receives a container and it is empty, then it's probably only stores a reference. To get this reference create a new Text object and pass the container as a parameter:

def myfunc(container):
    if isinstance(container, Container):
        if container:
            # stored container
            ...
        else:
            # unstored (reference-only) container
            reference = Text(container)

In boolean context empty containers evaluate to False and non-empty containers evaluate to True, so simple if container works exactly as we need.

Sometimes FileMaker may even pass a reference-only container as Text. In my tests if I just inserted a reference into a container and then immediatelly called a function using this field (without leaving the field), the container arrived into the function as Text, not as Container. So watch out: the code above may not be robust enough.

Initialization#Back to top

You can initialize a Container with another container, an iterable or a dictionary of type-data pairs, or with keyword parameters.

Container([container, **streams])
Container([iterable, **streams])
Container([dictionary, **streams])
Parameters
containerContainer

Container to copy.

iterableany Python iterable

An iterable (e.g. a list or a tuple) of type-data pairs. Each pair must be a two-item iterable; the first item must be a valid stream type (a four-character string) and the second item must be a valid data for this stream type (depends on type; see Overview).

dictionarya dictionary of streams

A dictionary of stream data with types as keys and data as values. Each key must be a valid stream type and value must be a valid data for this type (depends on type; see Overview).

streamsstream type and data passed as keywords

You can also pass stream type and data as keywords; this is probably the most natural method:

>>> c = Container(FILE='abc def ghi', FNAM='abc.txt')

This will only work for stream types that make valid Python identifiers. For example, the snd  type is not a valid Python identifier because it has a trailing space. To set such streams choose a different initialization method or add the stream after initialization.

Result and side effects

The constructor creates a new container and sets it to the specified values.

Discussion

Positional parameters are applied in order of appearance, so if you pass a container with FNAM and also pass FNAM as a keyword parameter, then the keyword parameter will overwrite the first FNAM.

Standard protocols#Back to top

Container supports mapping protocol, can iterate over keys or items, can be compared for equality, adn used in boolean context.

Boolean context#Back to top

In boolean context empty Containers are interpreted as False, non-empty Containers as True:

>>> c = Container()
>>> d = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> bool(c)
False
>>> bool(d)
True

Comparison#Back to top

Containers can be compared for equality:

>>> c = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> d = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> c == d
True
>>> c != d
False
>>> e = Container(FILE='jkl mno prq', FNAM='abc.txt')
>>> c == e
False
>>> f = Container(FILE='abc def ghi', FNAM='def.txt')
>>> c == f
False

Containers are not orderable, so they should not be compared with <, <=, >, or >= operators. Note that Python won't object if you do and will even produce some result because for historical reasons Python v2.x falls back to comparing object IDs and thus always gives some result when comparing any two objects.

Inclusion#Back to top

You can check if Container has a stream with the in keyword:

>>> from filemaker import Container
>>> c = container(FILE='abc def ghi', FNAM='abc.txt')
>>> 'FILE' in c
True
>>> 'JPEG' in c
False

Mapping#Back to top

Container has length (number of streams) and can access streams by their type:

>>> from filemaker import Container
>>> c = container(FILE='abc def ghi', FNAM='abc.txt')
>>> len(c)
2
>>> c['FILE']
'abc def ghi'

If this Container instance is modifiable, you can also change or delete streams:

>>> c['FILE'] = 'jkl mno pqr'
>>> c['FILE']
'jkl mno pqr'
>>> del c['FILE']
>>> 'FILE' in c
False

Containers also support some common mapping methods, such as get(), pop(), etc.; see the Methods section.

Methods#Back to top

bytes()#Back to top

Return all or selected bytes of a particular stream:

bytes(stream[, offset, size])
Parameters
streamtext, one of stream types

One of stream types, e.g. FILE, JPEG, etc. You can also specify special streams FNAM and SIZE.

offsetnumber

Optional index of the first byte to return, default 0.

sizenumber

Optional number of bytes to return; default is from offset to the end.

Result and side effects

The method returns bytes (str) of the specified stream. If you specify offset and/or size, it will only return this part of the stream. The method has no side effects.

Discussion

This method may be useful with large files that need to be read only partially, e.g. Zip files.

clear()#Back to top

Clear the container:

clear()
Parameters

The method takes no parameters.

Result and side effects

The method clears the container. It only works for modifiable containers; if the container is read-only, the method will raise the plugin.ReadOnlyError. The method returns no result.

get()#Back to top

Get the data of the specified stream or a default value:

get(stream[, default=Npne])
Parameters
streamtext, one of stream types

One of stream types, e.g. FILE, FNAM, etc.

defaultanything

Optional default value to return if the container has no such stream, by default None.

Result and side effects

The method returns the data of the specified stream or, if the container has no such stream, the supplied default value. The data of FNAM, if any, is filemaker.Text, the data of SIZE is a tuple of two integers, any other stream's data is a string (bytes). The method has no side effects.

items()#Back to top

Return a list of stream type-data pairs:

items()
Parameters

The method takes no parameters.

Result and side effects

The method returns a list of all stream type-value pairs in the container. The order of items is not defined. The method has no side effects.

iter_keys()#Back to top

Return an iterator over stream types:

iter_keys()
Parameters

The method takes no parameters.

Result and side effects

The method returns an iterator over stream types. The order of items is not defined. The method has no side effects.

iter_items()#Back to top

Return an iterator over stream type-data pairs:

iter_items()
Parameters

The method takes no parameters.

Result and side effects

The method returns an iterator over stream type-data pairs. The order of items is not defined. The method has no side effects.

keys()#Back to top

Return a list of stream types:

keys()
Parameters

The method takes no parameters.

Result and side effects

The method returns a list of all stream types in the container. The order of items is not defined. The method has no side effects.

pop()#Back to top

Return the data of the specified stream and delete it from the container:

pop(stream[, default])
Parameters
streamtext, one of stream types

Type of the stream to pop.

defaultanything

Optional default value to return if the container has no such stream. If you don't supply a value and the stream is not there, you'll get a KeyError.

Result and side effects

Return the specified stream's data. If the stream is not there and default is specified, return default. If the stream is not there and default is not specified, raise KeyError. The method only works on modifiable instances.

popitem()#Back to top

Return an arbitrary item and delete it from the container:

popitem()
Parameters

The method takes no parameters.

Result and side effects

Return an arbitrary stream type-data pair and at the same time remove it from the container. If the container is empty, raise KeyError. The method only works on modifiable instances.

readonly()#Back to top

Checks if this container instance is read-only:

Timestamp.readonly()
Parameters

The method takes no parameters.

Result and side effects

The method returns True if this instance is read-only, otherwise False. The method has no side effects.

set()#Back to top

Change the container's value:

set([container, **streams])
set([iterable, **streams])
set([dictionary, **streams])
Parameters
containerContainer

Container to copy.

iterableany Python iterable

An iterable (e.g. a list or a tuple) of type-data pairs. Each pair must be a two-item iterable; the first item must be a valid stream type (a four-character string) and the second item must be a valid data for this stream type (depends on type; see Overview).

dictionarya dictionary of streams

A dictionary of stream data with types as keys and data as values. Each key must be a valid stream type and value must be a valid data for this type (depends on type; see Overview).

streamsstream type and data passed as keywords

You can also pass stream type and data as keywords; this is probably the most natural method:

>>> c = Container()
>>> c.set(FILE='abc def ghi', FNAM='abc.txt')

This will only work for stream types that make valid Python identifiers. For example, the snd  type is not a valid Python identifier because it has a trailing space. To set such streams choose a different initialization method or add the stream after initialization.

All parameters are optional, but you must specify at least one.

Result and side effects

The method replaces the conteiner's value with the specified data. The method only works on modifiable containers.

Discussion

Positional parameters are applied in order of appearance, so if you pass a container with FNAM and also pass FNAM as a keyword parameter, then the keyword parameter will overwrite the first FNAM.

size()#Back to top

Return total size or size of a specified stream:

size([stream])
Parameters
streamtext, one of stream types

Optional stream type to get the size of.

Result and side effects

The method returns the size in bytes of the specified stream or, if the stream is omitted, of the whole container. The size does not include size of stream types themselves, only the size of data.

The method may raise TypeError if stream is not one of text types, ValueError if the stream is not a valid type identifier, KeyError if there is no such stream.

The method has no side effects.

Example#Back to top

>>> from filemaker import Container
>>> c = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> c.size('FILE')
11
>>> c.size('FNAM')
18
>>> c.size()
29

Here the size of file FILE stream is 11 bytes, exactly as it is. The size of FNAM does not match the lenght of the file name string (even if we add the file: prefix), because this stream has a special structure that looks very much unlike abc.txt. (Check it using bytes(), if you're interested.) Finally the total size is exactly the sum of these two.

update()#Back to top

Update container data:

set([container, **streams])
set([iterable, **streams])
set([dictionary, **streams])
Parameters
containerContainer

Container to copy.

iterableany Python iterable

An iterable (e.g. a list or a tuple) of type-data pairs. Each pair must be a two-item iterable; the first item must be a valid stream type (a four-character string) and the second item must be a valid data for this stream type (depends on type; see Overview).

dictionarya dictionary of streams

A dictionary of stream data with types as keys and data as values. Each key must be a valid stream type and value must be a valid data for this type (depends on type; see Overview).

streamsstream type and data passed as keywords

You can also pass stream type and data as keywords; this is probably the most natural method:

>>> c = Container(FILE='abc def ghi', FNAM='abc.txt')
>>> c.update(FILE='jkl mno pqr', FNAM='jkl.txt')

This will only work for stream types that make valid Python identifiers. For example, the snd  type is not a valid Python identifier because it has a trailing space. To set such streams choose a different initialization method or add the stream after initialization.

All parameters are optional, but you must specify at least one.

Result and side effects

The method updates conteiner's value with the specified data. The existing streams that are not there stay intact. The method only works on modifiable containers.

Discussion

Positional parameters are applied in order of appearance, so if you pass a container with FNAM and also pass FNAM as a keyword parameter, then the keyword parameter will overwrite the first FNAM.

Properties#Back to top

The Container type has no properties.