\r\n >>> obj['FOO']\r\n Traceback (most recent call last):\r\n ...\r\n FedoraConnectionException: ...No datastream could be found. Either there is no datastream for the digital object \"...\" with datastream ID of \"FOO\" OR there are no datastreams that match the specified date/time value of \"null\".\r\n\r\nDatastream Properties\r\n~~~~~~~~~~~~~~~~~~~~~\r\n\r\nA datastream has many properties, including label, state and createdDate, just\r\nlike the Fedora object:\r\n\r\n >>> print ds.label\r\n Dublin Core Record for this object\r\n\r\n >>> print ds.state\r\n A\r\n\r\nThere are different types of datastreams, this one is of type `X`, which means\r\nthe content is stored inline in the `FOXML file`_ . FOXML is the internal \r\nstorage format of Fedora.\r\n\r\n.. _FOXML file: http://fedora-commons.org/confluence/display/FCR30/Introduction+to+FOXML\r\n\r\n\r\n >>> print ds.controlGroup\r\n X\r\n\r\nA datastream can be versionable, this can be turned on or off.\r\n\r\n >>> ds.versionable\r\n True\r\n\r\nThe datastream also has a location, which is composed of the object pid,\r\nthe datastream id, and the version number\r\n\r\n >>> ds.location\r\n u'foo:...+DC+DC1.0'\r\n\r\nLet's change the label, and see what happens:\r\n\r\n >>> ds.label = u'Datastream Metadata'\r\n >>> ds.location\r\n u'foo:...+DC+DC.1'\r\n\r\n >>> ds.label = u'Datastream DC Metadata'\r\n >>> ds.location\r\n u'foo:...+DC+DC.2'\r\n\r\nThe location ID changes with every version, and old versions of the datastream\r\nare still available. The fcrepo client code contains no methods to retrieve\r\nold versions of datastreams or view the audit trail of objects. \r\nThe methods that implement this are available in the WADL API though.\r\n\r\nFedora can create checksums of the content stored in a datastream, \r\nby default checksums are disabled, if we set the checksumType property\r\nto MD5, Fedora will generate the checksum for us.\r\n\r\n >>> ds.checksumType \r\n u'DISABLED'\r\n >>> ds.checksumType = u'MD5'\r\n >>> ds.checksum # the checksum always changes between tests\r\n u'...'\r\n\r\nThere are some additional properties, not all of them can be set.\r\nHave a look at the `REST API Documentation`_ for a full list\r\n\r\n >>> ds.mimeType\r\n u'text/xml'\r\n >>> ds.size > 0\r\n True\r\n >>> ds.formatURI\r\n u'http://www.openarchives.org/OAI/2.0/oai_dc/'\r\n\r\n\r\nGetting and Setting Content - 1\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nWe can also get and set the content of the datastream:\r\n\r\n >>> xml = ds.getContent().read()\r\n >>> print xml\r\n \r\n My First Test Object\r\n foo:...\r\n \r\n\r\n >>> xml = xml.replace('My First Test Object', 'My First Modified Datastream')\r\n >>> ds.setContent(xml)\r\n\r\n\r\nGetting and Setting Content - 2\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nWe can also get and set the content directly, \r\nas if it is a dictionarie of dictionaries\r\n\r\n >>> print obj['DC']['title']\r\n [u'My First Modified Datastream']\r\n >>> obj['DC']['title'] = [u'My Second Modified Datastream']\r\n >>> print obj['DC']['title']\r\n [u'My Second Modified Datastream']\r\n\r\n\r\nSpecial Datastream: DC\r\n~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nThis `DC` datastream that is always available is actually a special kind of \r\ndatastream. The Dublin Core properties from this XML stream are stored in a\r\nrelational database which can be searched. The values are also used in the\r\nOAIPMH feed. Fedora uses the legacy `/elements/1.1/` namespace which contains\r\nthe following terms:\r\n\r\n * contributor\r\n * coverage\r\n * creator\r\n * date\r\n * description\r\n * format\r\n * identifier\r\n * language\r\n * publisher\r\n * relation\r\n * rights\r\n * source\r\n * subject\r\n * title\r\n * type\r\n\r\nView the `Dublin Core website`_ for a `description of these properties`_.\r\n\r\n.. _description of these properties: http://dublincore.org/documents/dcmi-terms/#H3\r\n.. _Dublin Core website: http://dublincore.org\r\n\r\nSince editing the Dublin Core XML data by hand gets a bit cumbersome, \r\nthe DC datastream allows access to the DC properties as if the datastream \r\nis a dictionary:\r\n\r\n >>> ds['title']\r\n [u'My Second Modified Datastream']\r\n\r\nThis can also be used to set values:\r\n\r\n >>> ds['subject'] = [u'fcrepo', u'unittest']\r\n >>> ds['description'].append(u'A test object from the fcrepo unittest')\r\n\r\n >>> for prop in sorted(ds): print prop\r\n description\r\n identifier\r\n subject\r\n title\r\n >>> 'subject' in ds\r\n True\r\n \r\n\r\nTo save this, we call the setContent method again, but this time with no\r\narguments. This will make the code use the values from the dictionary to\r\ngenerate the XML string for you\r\n\r\n >>> ds.setContent()\r\n >>> print ds.getContent().read()\r\n \r\n ...\r\n A test object from the fcrepo unittest\r\n ...\r\n \r\n\r\nInline XML Datastreams\r\n~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nLet's try adding some datastreams, for example, we want to store some XML data:\r\n\r\n >>> obj.addDataStream('FOOXML', '', \r\n ... label=u'Foo XML', \r\n ... logMessage=u'Added an XML Datastream')\r\n >>> obj.datastreams()\r\n ['DC', 'FOOXML']\r\n >>> print obj['FOOXML'].getContent().read()\r\n \r\n\r\nManaged Content Datastreams\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nWe can also add Managed Content, this will be stored and managed by fedora,\r\nbut it's not inline xml. The data is stored in a seperate file on \r\nthe harddrive. We do this by setting the controlGroup param to `M`\r\n\r\n >>> obj.addDataStream('TEXT', 'Hello!', label=u'Some Text',\r\n ... mimeType=u'text/plain', controlGroup=u'M', \r\n ... logMessage=u'Added some managed text')\r\n >>> obj.datastreams()\r\n ['DC', 'FOOXML', 'TEXT']\r\n >>> ds = obj['TEXT']\r\n >>> ds.size == 0 or ds.size == 6 # this does not work in Fedora 3.3\r\n True\r\n >>> ds.getContent().read()\r\n 'Hello!'\r\n\r\nThis is perfectly fine for small files, however when you don't want to hold\r\nthe whole file in memory you can also supply a file stream. Let's make a 3MB\r\nfile:\r\n\r\n >>> import tempfile, os\r\n >>> fp = tempfile.NamedTemporaryFile(mode='w+b', delete=False)\r\n >>> filename = fp.name\r\n >>> fp.write('foo' * (1024**2))\r\n >>> fp.close()\r\n >>> os.path.getsize(filename)\r\n 3145728...\r\n\r\nNow we'll open the file and stream it to Fedora. We then read the whole thing\r\nin memory and see if it's the same size:\r\n\r\n >>> fp = open(filename, 'r')\r\n >>> ds.setContent(fp)\r\n >>> fp.close()\r\n >>> content = ds.getContent().read()\r\n >>> len(content)\r\n 3145728...\r\n >>> os.remove(filename) \r\n\r\nExternally Referenced Datastreams\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nFor large files it might not be convenient to store them inside Fedora. \r\nIn this case the file can be hosted externally, and we store a datastream\r\nof controlGroup type `E` (Externally referenced)\r\n\r\n >>> obj.addDataStream('URL', controlGroup=u'E',\r\n ... location=u'http://pypi.python.org/fcrepo')\r\n >>> obj.datastreams()\r\n ['DC', 'FOOXML', 'TEXT', 'URL']\r\n\r\nThis datastream does not have any content, so trying to read the\r\ncontent will result in an error\r\n\r\n >>> ds = obj['URL']\r\n >>> ds.getContent()\r\n Traceback (most recent call last):\r\n ...\r\n FedoraConnectionException:...\"Error getting http://pypi.python.org/fcrepo\" .\r\n\r\nWe can get the location though:\r\n\r\n >>> ds.location\r\n u'http://pypi.python.org/fcrepo'\r\n\r\nThe last of the datastream types is an externally referenced stream that \r\nredirects. This datastream has controlGroup `R` (Redirect Referenced)\r\n\r\n >>> obj.addDataStream('HOMEPAGE', controlGroup=u'R',\r\n ... location=u'http://pypi.python.org/fcrepo')\r\n >>> obj.datastreams()\r\n ['DC', 'FOOXML', 'TEXT', 'URL', 'HOMEPAGE']\r\n\r\nThis datastream works the same as an externally referenced stream. \r\n\r\nDeleting Datastreams\r\n~~~~~~~~~~~~~~~~~~~~\r\n\r\nA datastream can be deleted by using the python del keyword on the object,\r\nor by calling the delete method on a datastream.\r\n\r\n >>> len(obj.datastreams())\r\n 5\r\n >>> ds = obj['HOMEPAGE']\r\n >>> ds.delete(logMessage=u'Removed Homepage DS') \r\n >>> len(obj.datastreams())\r\n 4\r\n >>> del obj['URL']\r\n >>> len(obj.datastreams())\r\n 3\r\n\r\nAnother Special Datastream: RELS-EXT\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nBesides the special `DC` datastream, there is another special datastream \r\ncalled `RELS-EXT`.\r\nThis datastream should contain `flat` RDFXML data which will be indexed in a\r\ntriplestore. The `RELS-EXT` datastream has some additional methods to assist in \r\nworking with the RDF data.\r\n\r\nTo create the RELS-EXT stream we don't need to supply an RDFXML file, it will\r\ncreate an empty one if no data is send.\r\n\r\n >>> obj.addDataStream('RELS-EXT')\r\n >>> ds = obj['RELS-EXT']\r\n\r\nNow we can add some RDF data. Each predicate contains a list of values, each\r\nvalue is a dictionary with a value and type key, and optionally a lang and\r\ndatatype key. This is identical to the `RDF+JSON format`_.\r\n\r\n.. _RDF+JSON format: http://n2.talis.com/wiki/RDF_JSON_Specification\r\n\r\n >>> from fcrepo.utils import NS\r\n >>> ds[NS.rdfs.comment].append(\r\n ... {'value': u'A Comment set in RDF', 'type': u'literal'})\r\n >>> ds[NS.rdfs.comment]\r\n [{'type': u'literal', 'value': u'A Comment set in RDF'}]\r\n >>> NS.rdfs.comment in ds\r\n True\r\n >>> for predicate in ds: print predicate\r\n http://www.w3.org/2000/01/rdf-schema#comment\r\n\r\nTo save this we call the setContent method without any data. \r\nThis will serialise the RDF statements to RDFXML and perform the save action:\r\n \r\n >>> ds.setContent()\r\n >>> print ds.getContent().read()\r\n \r\n \r\n A Comment set in RDF\r\n \r\n \r\n\r\nWe are not allowed to add statements using the `DC` namespace.\r\nThis will result in an error. I suppose this is because it should be set \r\nthrough the `DC` datastream.\r\n\r\n >>> ds[NS.dc.title].append({'value': u'A title', 'type': 'literal'})\r\n >>> ds.setContent()\r\n Traceback (most recent call last):\r\n ...\r\n FedoraConnectionException: ... The RELS-EXT datastream has improper relationship assertion: dc:title.\r\n\r\nWe can also use RDF to create relations between objects. For example we can add\r\na relation using the Fedora isMemberOfCollection which can be used to group\r\nobjects into collections that are used in the OAIPMH feed.\r\n\r\n >>> colpid = client.getNextPID(u'foo')\r\n >>> collection = client.createObject(colpid, label=u'A test Collection')\r\n >>> ds[NS.fedora.isMemberOfCollection].append(\r\n ... {'value': u'info:fedora/%s' % colpid, 'type':u'uri'})\r\n >>> ds.setContent()\r\n >>> print ds.getContent().read()\r\n \r\n \r\n \r\n A Comment set in RDF\r\n \r\n \r\n\r\n >>> print ds.predicates()\r\n ['http://www.w3.org/2000/01/rdf-schema#comment', 'info:fedora/fedora-system:def/relations-external#isMemberOfCollection']\r\n\r\nNotice that the Fedora PID needs to be converted to an URI before it can be\r\nreferenced in RDF, this is done by prepending `info:fedora/` to the PID.\r\n\r\nService Definitions and Object Methods\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\r\nBesides datastreams, a Fedora object can have methods registered to it through\r\nservice definitions. We don't provide direct access to the service definitions\r\nbut assume that all the methods have unique names.\r\n\r\n >>> obj.methods()\r\n ['viewObjectProfile', 'viewMethodIndex', 'viewItemIndex', 'viewDublinCore']\r\n\r\n >>> print obj.call('viewDublinCore').read()\r\n \r\n ...\r\n | My Second Modified Datastream | \r\n ...\r\n \r\n\r\nSearching Objects\r\n~~~~~~~~~~~~~~~~~\r\n\r\nFedora comes with 2 search functionalities: a fielded query search and a simple query search.\r\nThey both search data from the `DC` datastream and the Fedora object properties. \r\n\r\nThe fielded search query can search on the following fields:\r\n\r\n * cDate \r\n * contributor \r\n * coverage \r\n * creator \r\n * date \r\n * dcmDate \r\n * description \r\n * format \r\n * identifier \r\n * label \r\n * language \r\n * mDate \r\n * ownerId \r\n * pid \r\n * publisher \r\n * source \r\n * state \r\n * subject \r\n * title \r\n * type \r\n * rights\r\n\r\nFedora has a query syntax where you can enter one or more conditions, separated by space. Objects matching all conditions will be returned.\r\n\r\nA condition is a field (choose from the field names above) followed by an operator, followed by a value.\r\n\r\nThe = operator will match if the field's entire value matches the value given.\r\nThe ~ operator will match on phrases within fields, and accepts the ? and * wildcards.\r\nThe <, >, <=, and >= operators can be used with numeric values, such as dates.\r\n\r\nExamples:\r\n\r\n pid~demo:* description~fedora\r\n Matches all demo objects with a description containing the word fedora.\r\n\r\n cDate>=1976-03-04 creator~*n*\r\n Matches objects created on or after March 4th, 1976 where at least one of the creators has an n in their name.\r\n\r\n mDate>2002-10-2 mDate<2002-10-2T12:00:00\r\n Matches objects modified sometime before noon (UTC) on October 2nd, 2002\r\n\r\nSo let's create 5 objects which we can use to search on:\r\n\r\n >>> pids = client.getNextPID(u'searchtest', numPIDs=5)\r\n >>> for pid in pids: client.createObject(pid, label=u'Search Test Object')\r\n \r\n \r\n \r\n \r\n \r\n\r\nNow we'll search for these objects with a pid search, we also want the label\r\nreturned from the search.\r\n\r\n >>> client.searchObjects(u'pid~searchtest:*', ['pid', 'label'])\r\n \r\n\r\nThe search returns a generator, by default it queries the server for the\r\nfirst 10 objects, but if you iterate through the resultset and come to the end\r\nthe next batch will automatically be added. \r\n\r\nTo illustrate this we will query with a batch size of 2:\r\n\r\n >>> results = client.searchObjects(u'pid~searchtest:*', ['pid', 'label'],\r\n ... maxResults=2)\r\n >>> result_list = [r for r in results]\r\n >>> len(result_list) >= 5\r\n True\r\n >>> result_list[0]['pid']\r\n [u'searchtest:...']\r\n >>> result_list[0]['label']\r\n [u'Search Test Object']\r\n\r\nAs shown we actually get more results then the max of 2, but the client asks\r\nFedora for results in batches of 2 while we iterate through the results \r\ngenerator.\r\n\r\nWhen we want to search in all fields, we just have to drop the condition 'pid:',\r\nand specify 'terms=True'. The search is case-insensitive, and use * or ? as wildcard.\r\n\r\n >>> client.searchObjects(u'searchtest*', ['pid', 'label'], terms=True)\r\n \r\n\r\n\r\nRDF Index Search\r\n~~~~~~~~~~~~~~~~\r\n\r\nBesides searching the DC datastream in the relational database, \r\nit's also possible to query the RELS-EXT datastream through the triplestore \r\nin the SPARQL language.\r\n\r\nLet's find all objects that are part of the collection we created above in the\r\nRELS-EXT datastream example\r\n\r\n >>> sparql = '''prefix fedora: <%s>\r\n ... select ?s where {?s fedora:isMemberOfCollection .}\r\n ... ''' % (NS.fedora, colpid)\r\n >>> result = client.searchTriples(sparql)\r\n >>> result\r\n \r\n >>> result = list(result)\r\n >>> len(result)\r\n 1\r\n >>> result[0]['s']['value']\r\n u'info:fedora/foo:...'\r\n\r\nOther output formats and query languages can be specified as parameters, by\r\ndefault only SPARQL is supported.\r\n\r\nThe searchTriples method also has a `flush` argument. \r\nIf you change a RELS-EXT datastream in Fedora, the triplestore is actually not\r\nupdated! You have to set this flush param when you're searching to `true` to\r\nmake sure the triplestore is updated. By default Fedora sets the flush \r\nparameter to `false` which is understandable for performance reasons but \r\ncan be very confusing.\r\nThis library sets the param to `true` by default, which is not always very \r\nefficient, but you are sure the triplestore is up to date.\r\n\r\n\r\nFCRepo Changes\r\n==============\r\n\r\n1.1 (2010-11-04)\r\n----------------\r\n\r\n - Added simple searching (via searchObject), courtesy of Steen Manniche\r\n - Removed buildout versions from buildout.cfg\r\n - Fixed bug when decoding empty text\r\n - Updated readme\r\n\r\n\r\n1.0 (2010-09-30)\r\n----------------\r\n \r\n - Added support for Fedora3.4\r\n - Changed contact info, switched from Subversion to Mercurial\r\n\r\nChanges\r\n~~~~~~~\r\n - Fixed bug triggered when retrieving DC datastream values that\r\n contain no text\r\n\r\nfcrepo 1.0b2 (2010-05-17)\r\n-------------------------\r\n\r\nChanges\r\n~~~~~~~\r\n - Full Windows compatibility through patches from Owen Nelson\r\n - Bugfix in datastreams handling\r\n\r\nfcrepo 1.0b1 (2010-05-03)\r\n-------------------------\r\n\r\nChanges\r\n~~~~~~~\r\n - Initial Code release with working API-A, API-M\r\n search and index search.",
"description_content_type": null,
"docs_url": null,
"download_url": "UNKNOWN",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "http://infrae.com/download/fedoracommons/fcrepo",
"keywords": "",
"license": "BSD",
"maintainer": "",
"maintainer_email": "",
"name": "fcrepo",
"package_url": "https://pypi.org/project/fcrepo/",
"platform": "UNKNOWN",
"project_url": "https://pypi.org/project/fcrepo/",
"project_urls": {
"Download": "UNKNOWN",
"Homepage": "http://infrae.com/download/fedoracommons/fcrepo"
},
"release_url": "https://pypi.org/project/fcrepo/1.1/",
"requires_dist": null,
"requires_python": null,
"summary": "API implementation for the Fedora Commons Repository platform",
"version": "1.1"
},
"last_serial": 220825,
"releases": {
"1.0": [
{
"comment_text": "",
"digests": {
"md5": "5b20e12677d0305afe5daae03710e28e",
"sha256": "532268a5c45d7625655854266400047298774f614e8d002bdbb9bb5364356318"
},
"downloads": -1,
"filename": "fcrepo-1.0.tar.gz",
"has_sig": false,
"md5_digest": "5b20e12677d0305afe5daae03710e28e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 26192,
"upload_time": "2010-09-30T11:12:18",
"url": "https://files.pythonhosted.org/packages/ff/14/08385b9805f88c57d2567966fc82090c0a98f802e64b1cb577ab6c0dbc49/fcrepo-1.0.tar.gz"
}
],
"1.0b1": [
{
"comment_text": "",
"digests": {
"md5": "196ad5465ec0d709cdb29d64adafd130",
"sha256": "ff05bdbf514669b26998e203b7e7d40004879f264fc4266b3e92c2df094f0039"
},
"downloads": -1,
"filename": "fcrepo-1.0b1.tar.gz",
"has_sig": false,
"md5_digest": "196ad5465ec0d709cdb29d64adafd130",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 25106,
"upload_time": "2010-05-03T14:46:47",
"url": "https://files.pythonhosted.org/packages/c0/6f/ed7e87fe45ec25f9cc8ff0deacd1f66df5d7822944a13be1a6a5238bd766/fcrepo-1.0b1.tar.gz"
}
],
"1.0b2": [
{
"comment_text": "",
"digests": {
"md5": "655f1b404c7cf6a2982108e67fa95c31",
"sha256": "2e7a010e902ee5263f6f4b6a4172344f1cefe26547ad2b3cdd924c600a5c5b3f"
},
"downloads": -1,
"filename": "fcrepo-1.0b2.tar.gz",
"has_sig": false,
"md5_digest": "655f1b404c7cf6a2982108e67fa95c31",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 25074,
"upload_time": "2010-05-17T16:07:43",
"url": "https://files.pythonhosted.org/packages/8f/bf/a18f894d0a94a1e873dd5b5ed4620bb49955fea056517f2fef4950c87fbf/fcrepo-1.0b2.tar.gz"
}
],
"1.1": [
{
"comment_text": "",
"digests": {
"md5": "61bafa0ca88316a7e87de5be82c7688a",
"sha256": "87bb2d30d8effc281f64054a1269431c96f57477be0c0eff774a31cc27beb82d"
},
"downloads": -1,
"filename": "fcrepo-1.1.tar.gz",
"has_sig": false,
"md5_digest": "61bafa0ca88316a7e87de5be82c7688a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 36651,
"upload_time": "2010-11-04T17:02:22",
"url": "https://files.pythonhosted.org/packages/81/58/a9933d6d93b5f78f6715371b94caca2d63a055600cc6cc1d0b831b62a2fd/fcrepo-1.1.tar.gz"
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "61bafa0ca88316a7e87de5be82c7688a",
"sha256": "87bb2d30d8effc281f64054a1269431c96f57477be0c0eff774a31cc27beb82d"
},
"downloads": -1,
"filename": "fcrepo-1.1.tar.gz",
"has_sig": false,
"md5_digest": "61bafa0ca88316a7e87de5be82c7688a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 36651,
"upload_time": "2010-11-04T17:02:22",
"url": "https://files.pythonhosted.org/packages/81/58/a9933d6d93b5f78f6715371b94caca2d63a055600cc6cc1d0b831b62a2fd/fcrepo-1.1.tar.gz"
}
]
}