{"id":28298630,"url":"https://github.com/ubleipzig/marcx","last_synced_at":"2025-10-04T23:28:40.059Z","repository":{"id":9141596,"uuid":"10933056","full_name":"ubleipzig/marcx","owner":"ubleipzig","description":"`pymarc.Record` subclass for easier MARC21 manipulation","archived":false,"fork":false,"pushed_at":"2023-11-10T14:58:58.000Z","size":134,"stargazers_count":10,"open_issues_count":2,"forks_count":6,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-30T06:26:13.216Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ubleipzig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-06-25T08:41:23.000Z","updated_at":"2024-05-06T15:35:24.000Z","dependencies_parsed_at":"2022-09-08T08:02:18.829Z","dependency_job_id":null,"html_url":"https://github.com/ubleipzig/marcx","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ubleipzig/marcx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubleipzig%2Fmarcx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubleipzig%2Fmarcx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubleipzig%2Fmarcx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubleipzig%2Fmarcx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ubleipzig","download_url":"https://codeload.github.com/ubleipzig/marcx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubleipzig%2Fmarcx/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259737919,"owners_count":22903873,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-23T06:14:24.418Z","updated_at":"2025-10-04T23:28:34.995Z","avatar_url":"https://github.com/ubleipzig.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"README\n======\n\n`marcx.Record` is a small extension to\n[pymarc.Record](https://github.com/edsu/pymarc/blob/056cea129758c20068aec11a4cb148d65987d905/pymarc/record.py#L72),\nthat adds a few shortcuts: `itervalues`, `test`, `add` and `remove`.\n\n[![pypi version](http://img.shields.io/pypi/v/marcx.svg?style=flat)](https://pypi.python.org/pypi/marcx)\n\n\u003c!---\n[![PyPi version](https://img.shields.io/pypi/v/marcx.svg)](https://crate.io/packages/marcx/)\n--\u003e\n\nCompatibility Notes\n-------------------\n\n* marcx 0.3.0 is **only compatible with pymarc 5** or higher; if for some reason you need the older pymarc, you will need to fix the versions for both marcx and pymarc, e.g. `pymarc==4.2.2` and `marcx==0.2.12`\n* since version 0.2.0, both Python 2 and 3 should be supported\n\n\nInstallation\n------------\n\nIt's on [pypi](https://pypi.python.org/pypi/marcx), so just:\n\n    $ pip install marcx\n\nPython 2.6 or higher required. If you want to run the tests, too, you'll need 2.7 or higher. Python 3 should work, too.\n\nOverview\n--------\n\nIterate over field values quickly with `itervalues` and `iterfields`:\n\n```python\n\u003e\u003e\u003e from urllib import urlopen # from urllib.request import urlopen\n\u003e\u003e\u003e import marcx\n\u003e\u003e\u003e record = marcx.Record(data=urlopen(\"http://goo.gl/lfJnw9\").read())\n\n\u003e\u003e\u003e record.itervalues('020.a')\n\u003cgenerator object values at 0x2d97690\u003e\n\n\u003e\u003e\u003e set(record.itervalues('020.a'))\nset(['020161622X'])\n```\n\nA variable number of specs can be passed:\n\n```python\n\u003e\u003e\u003e set(record.itervalues('001', '005', '700.a'))\nset(['20040816084925.0', 'Thomas, David,', '11778504'])\n```\n\nIterate over fields, but instead of just returning the values, return\ntuples of the form `(field, value)`:\n\n```python\n\u003e\u003e\u003e for fv in record.iterfields('020.a'): print(fv)\n(\u003cpymarc.field.Field object at 0x18e7990\u003e, '020161622X')\n```\n\n----\n\nTest a field or subfield with predicates. Pass any function, that returns\na boolean value to `test` and it gets evaluated over all values\n(pass `all=True` if *all* values must evaluate to `True` in the test function):\n\n```python\n\u003e\u003e\u003e record.test('001', lambda v: sum([int(d) for d in v]) == 33)\nTrue\n\n\u003e\u003e\u003e record.test('020.a', lambda v: v.startswith('978'), all=True)\nFalse\n```\n\n----\n\nTest, if a record has any values at all in a certain field or subfield:\n\n```python\n\u003e\u003e\u003e record.has('020')\nTrue\n\u003e\u003e\u003e record.has('020.a')\nTrue\n\u003e\u003e\u003e record.has('020.x')\nFalse\n```\n\n----\n\nAdd and remove fields with one line (control fields get `data`, non-control\nfields get subfields via [keyword\narguments](https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments)):\n\n```python\n\u003e\u003e\u003e record = marcx.Record()\n\u003e\u003e\u003e record.add('001', data='12345')\n\u003e\u003e\u003e record.add('020', a='9780201616224')\n\u003e\u003e\u003e record.add('020', a='020161622X')\n\u003e\u003e\u003e record.remove('001')\n```\n\nNote: *The order of the keyword arguments is not preserved* in Python 3.5 or\nearlier. However, Python 3.6 implemented [PEP 468: Preserving Keyword Argument\nOrder](https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep468) and\ntherefore subfields actually will be added in the order they are specified.\n\nAdd repeated subfields:\n\n```python\n\u003e\u003e\u003e record.remove('020.a')\n\u003e\u003e\u003e record.add('020', a=['9780201616224', '020161622X'])\n```\n\nAdd fields with many subfields at once:\n\n```python\n\u003e\u003e\u003e record.add('990', a='1', b='2', c='3', d='5', e='6')\n```\n\nAdd numeric subfield with underscores:\n\n```python\n\u003e\u003e\u003e record.add('991', _0='Zero', _1='One', _9='Nine')\n```\n\n----\n\nFlatten all values in a MARC record, e.g. to build corpuses:\n\n```python\n\u003e\u003e\u003e record = marcx.Record(data=urlopen(\"http://goo.gl/lfJnw9\").read())\n\u003e\u003e\u003e record.flatten()\n['11778504',\n '20040816084925.0',\n '990802s2000    mau      b    001 0 eng',\n '(DLC)   99043581',\n '0',\n 'vip',\n 'orignew',\n '1',\n 'ocip',\n '19',\n 'y-gencatlg',\n '0',\n 'acquire',\n '2 shelf copies',\n 'policy default',\n \"pc05 to ja00 08-02-99; jf05 to subj. 08/02/99; jf11 to sl 08-03-99; ...\",\n 'ADDED COPIES: another copy to ASCD ps15 01-12-00',\n '99043581',\n '020161622X',\n 'DLC',\n 'DLC',\n 'DLC',\n 'pcc',\n '0',\n 'QA76.6',\n '.H857 2000',\n '0',\n '0',\n '005.1',\n '21',\n '0',\n '1',\n 'Hunt, Andrew,',\n '1964-',\n '1',\n 'The pragmatic programmer :',\n 'from journeyman to master /',\n 'Andrew Hunt, David Thomas.',\n '4',\n 'Reading, Mass :',\n 'Addison-Wesley,',\n '2000.',\n 'xxiv, 321 p. ;',\n '24 cm.',\n 'Includes bibliographical references.',\n 'Computer programming.',\n '0',\n '1',\n 'Thomas, David,',\n '1956-',\n 'GAP']\n```\n\nMore examples\n-------------\n\nAdding a control field (001-009):\n\n```python\n\u003e\u003e\u003e import pymarc\n\n\u003e\u003e\u003e # w/ Record\n\u003e\u003e\u003e field = pymarc.Field('001', data='12345')\n\u003e\u003e\u003e record.add_field(field)\n\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.add('001', data='21345')\n```\n\nAdding a non-control field (010-999):\n\n```python\n\u003e\u003e\u003e # w/ Record\n\u003e\u003e\u003e field = pymarc.Field('852', [' ',' '], subfields = ['a', 'DE-15'])\n\u003e\u003e\u003e record.add_field(field)\n\n\u003e\u003e\u003e # w/ Record, [' ',' '] are the default indicators\n\u003e\u003e\u003e record.add('852', a='DE-15')\n```\n\nAdding multiple subfields to a non-control field at once:\n\n```python\n\u003e\u003e\u003e # w/ Record\n\u003e\u003e\u003e field = pymarc.Field('980', [' ',' '], subfields=['a', '12376'])\n\u003e\u003e\u003e record.add_field(field)\n\u003e\u003e\u003e field = pymarc.Field('980', [' ',' '], subfields=['b', '001'])\n\u003e\u003e\u003e record.add_field(field)\n\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.add('980', a='12376', b='001')\n```\n\nAdding multiple subfields to a non-control field at once with different indicators:\n\n```python\n\u003e\u003e\u003e # w/ Record\n\u003e\u003e\u003e field = pymarc.Field('041', ['0',' '], subfields=['a', 'ger'])\n\u003e\u003e\u003e record.add_field(field)\n\u003e\u003e\u003e field = pymarc.Field('041', ['0','7'], subfields=['a', 'dt.'])\n\u003e\u003e\u003e record.add_field(field)\n\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.add('041', a='ger', indicators=['0',' '])\n\u003e\u003e\u003e record.add('041', a='dt.', indicators=['0','7'])\n```\n\nSpecify indicators as strings (since an indicator is just a single char):\n\n```python\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.add('041', a='ger', indicators='0 ')\n\u003e\u003e\u003e record.add('041', a='dt.', indicators='07')\n```\n\nRemove a field:\n\n```python\n\u003e\u003e\u003e # w/ Record\n\u003e\u003e\u003e __001 = record['001']\n\u003e\u003e\u003e record.remove_field(__001)\n\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.remove('001') # removes all 001 fields\n```\n\nExample from [pymarc.Field](https://github.com/edsu/pymarc/blob/master/pymarc/field.py) source:\n\n```python\n\u003e\u003e\u003e # w/ Record\n... field = Field(\n... tag='245',\n... indicators=['0', '1'],\n... subfields=[\n...     'a', 'The pragmatic programmer : ',\n...     'b', 'from journeyman to master /',\n...     'c', 'Andrew Hunt, David Thomas.'\n... ])\n\u003e\u003e\u003e record.add_field(field)\n\n\u003e\u003e\u003e # w/ marcx.Record\n\u003e\u003e\u003e record.add('245',\n... a='The pragmatic programmer : ',\n... b='from journeyman to master /',\n... c='Andrew Hunt, David Thomas.',\n... indicators='01')\n```\n\nCatching basic errors\n---------------------\n\nSee also: [00X - Control Fields-General Information](http://www.loc.gov/marc/bibliographic/bd00x.html)\n\n```python\n\u003e\u003e\u003e obj.add('001', a='Yeah')\n...\nValueError: data must not be empty\n\n\u003e\u003e\u003e obj.add('010', data='Yeah')\n...\nValueError: non-control fields take no data\n\n\u003e\u003e\u003e obj.add('001', data='...', indicators='00')\n...\nValueError: control fields take no indicators\nsee: http://www.loc.gov/marc/bibliographic/bd00x.html\n\n\u003e\u003e\u003e obj.add('001', data='...', a='X')\n...\nValueError: control fields take no subfields\nsee: http://www.loc.gov/marc/bibliographic/bd00x.html\n```\n\nDevelopment\n-----------\n\nEasiest way to run the tests is via [nose](https://nose.readthedocs.org/en/latest/):\n\n    $ nosetests\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubleipzig%2Fmarcx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubleipzig%2Fmarcx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubleipzig%2Fmarcx/lists"}